我想知道是否有更好的方法来解决我忽略的问题。 (我正在寻找第二个意见)
我想创建一种使用“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;
}
}
答案 0 :(得分: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
类中执行名称更改,而不会破坏绑定。
列名仍然是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
}
// ...
};
我向你提出了从表达式中挖掘属性描述符的问题:)