2

我想知道是否有更好的方法来解决我忽略的这个问题。(我正在寻找第二个意见)

我想创建一种通用且简单的方法来使用“Oracle.DataAccess.Client”将对象绑定到数据库读取器查询。

为了做到这一点,我最初想创建一个继承自 OracleCommand 的对象;但是,OracleCommand 是一个密封的对象。

为了解决这个问题,我决定创建一个扩展方法,该方法尝试将对象映射到数据库中每一行的通用列。

编辑:在我的场景中,我知道数据库会是什么样子;但是,在运行时间之前,我不知道数据库在哪里。即数据库可能已提前传输,最终用户将在运行时指定数据库的凭据。

这是实现:

public static T[] Bind<T>(this OracleCommand oe, Binding binding, CommandBehavior Behavior = CommandBehavior.Default)
    {
        List<T> ret = new List<T>();

        using (var reader = oe.ExecuteReader(Behavior))
        {
            while (reader.Read())
            {
                T unknownObj = (T)Activator.CreateInstance(typeof(T));
                for (int i = 0; i < binding.GetBindCount(); i++)
                {
                    var propinfo = unknownObj.GetType().GetProperties().ToList();
                    var prop = propinfo.Find((p) => p.Name == binding.GetBindValue(i, true));
                    prop.SetValue(unknownObj, reader[binding.GetBindValue(i, false)]);
                }
                ret.Add(unknownObj);
            }
        }
        return ret.ToArray();
    }
}

public class Binding
{

    List<BindingMap> _map = new List<BindingMap>();


    public void AddBind(String VariableName, String ColumnName)
    {
        _map.Add(new BindingMap(VariableName, ColumnName));
    }
    public String GetBindValue(int index, bool IsVariable = true)
    {
        var a = _map.ToArray();
        return (IsVariable) ? a[index].Variable : a[index].Column;
    }

    public int GetBindCount()
    {
        return _map.Count;
    }
}

public class BindingMap
{
    public String Column;
    public String Variable;

    public BindingMap(String v, String c)
    {
        Variable = v;
        Column = c;
    }
}

有没有更好的方法可以做到这一点,我忽略了,或者这是一个声音?

它在实际代码中的使用方式是这样的:

 static void Main()
    {           
        Binding b = new Binding();
        b.AddBind("CreatedBy", "Create_by");


        using (var Conn = new OracleConnection())
        {
            Conn.ConnectionString = od.Options.GetConnectionString();
            using (var Command = new OracleCommand())
            {
                Command.Connection = Conn;
                Command.CommandText = "Select * From Accounts";

                Conn.Open();

                var a = Command.Bind<Account>(b);
                foreach (Account e in a)
                {
                    Console.WriteLine(e.CreatedBy);
                }
            }
        }
        Console.Read();
    }

    public class Account
    {
        public String CreatedBy
        {
            get;
            set;
        }

    }
4

1 回答 1

0

作为一种更好的方法,您可以像 Telerik 那样指定绑定属性:使用 Linq 表达式。这是用法。代替 :

AddBind("CreatedBy", "Created_by");

你会写

AddBind( x => x.CreatedBy, "Created_by");

您会获得稍强的打字机会。的签名AddBind将是:

public void AddBind<T>(Expression<Func<Account, T>> variable, string columnName) {
    // ...
}

但我不会进入泛型函数的方式。我宁愿重载一个非泛型函数:

public void AddBind(Expression<Func<Account, double>> variable, string columnName) {
    // Add binding for double
}

public void AddBind(Expression<Func<Account, DateTime>> variable, string columnName) {
    // Add binding for DateTime
}

// ...

然后将根据映射对象的类型选择绑定类型。这可以防止您对属性进行错误命名,因此您可以在Account不破坏绑定的情况下在类中执行名称更改。

列名仍然必须是 a string,抱歉。

当然,泛化的方法是使你的BindingMap泛化。(将您的业务类作为类型参数)

class BindingMap<BusinessClass> {
  // ....

    public void AddBind(Expression<Func<BusinessClass, double>> variable, string columnName) {
        // Add binding for double
    }

    public void AddBind(Expression<Func<BusinessClass, DateTime>> variable, string columnName) {
        // Add binding for DateTime
    }

    // ... 
};

我把从表达式中挖掘属性描述符的问题留给你作为练习:)

于 2013-10-01T15:22:44.967 回答