dynamic真有如此奇技? ADO.NET 虽有怀疑,但它想到曾经看过一部叫《阿甘正传》的电影,里面的阿甘虽然是弱智人,但参军时练就乒乓奇技,后来还和中国国手同台竞技。想到这,ADO.NET 认为不能因为对方弱智就不相信对方的话,这是很不礼貌很不绅士的人才会做的事,所以它相信了dynamic。
dynamic 果真不负众望,三两脚猫功夫就交出成果了。
dynamic重构后的数据库操作
using (dynamic command = connection.CreateDynamicCommand())
{
//执行查询SQL
IEnumerable<dynamic> toptenOrders = command("select Top 10 * from Orders");
foreach (dynamic order in toptenOrders)
{
Console.WriteLine("OrderID: {0}, OrderDate: {1}", order.OrderID, order.OrderDate);
}
//执行带参数的SQL
IEnumerable<dynamic> customerOrders = command("select * from Orders where CustomerID = @CustomerID",
CustomerID: "ALFKI");
foreach (dynamic order in customerOrders)
{
Console.WriteLine("OrderID: {0}, OrderDate: {1}", order.OrderID, order.OrderDate);
}
//调用存储过程
IEnumerable<dynamic> orders = command.CustOrdersOrders(CustomerID: "ALFKI");
foreach (dynamic order in orders)
{
Console.WriteLine("OrderID: {0}, OrderDate: {1}", order.OrderID, order.OrderDate);
}
}
要知道 ADO.NET 可不是.NET菜鸟,它看到 command("select Top 10 * from Orders"); 第一感觉认为吃了dynamic药的command有可能是委托类型,而看到后面的 command.CustOrdersOrders(CustomerID: "ALFKI"); 不得不否决了前面的看法。dynamic到底是什么东西?可以这样认为,dynamic什么东西都是;也可以认为,dynamic不是什么东西!
ADO.NET 知道任何.NET写的再高深的代码在reflector下都会现出原形,通过对 command 解剖,立刻明白原来自己跟《美丽心灵》的纳什教授一样纠缠于一种不存在的幻想不能自拔,reflector告诉我们:dynamic实际上是不存在的!
还是鲁迅叔叔说的好,世界上本没有dynamic,只是微软对委托封装得太牛了,也便有了dynamic。
结语
聪明的你知道command是怎么实现了吗?不妨先想想,然后展开下面的代码看看是否与你想的一致。
注:本文存储过程部分参考了微型ORM.
public static class Extensions
{
public static DynamicCommand CreateDynamicCommand(this DbConnection connection)
{
return new DynamicCommand(connection);
}
}
/// <summary>
/// 动态Command
/// </summary>
public class DynamicCommand : DynamicObject, IDisposable
{
public DbConnection Connection { get; set; }
public DynamicCommand(DbConnection connection)
{
this.Connection = connection;
}
//实现SQL语句查询
public override bool TryInvoke(InvokeBinder binder, object[] args, out object result)
{
if (args.Length == 0) throw new ArgumentException("args must has value");
result = Execute(args[0].ToString(), CommandType.Text, binder.CallInfo.ArgumentNames, args.Skip(1).ToArray());
return true;
}
//实现存储过程
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (binder.CallInfo.ArgumentNames.Count != binder.CallInfo.ArgumentCount)
{
throw new ArgumentException("All parameters must be named");
}
result = Execute(binder.Name, CommandType.StoredProcedure, binder.CallInfo.ArgumentNames, args);
return true;
}
/// <summary>
/// 执行SQL查询
/// </summary>
/// <param name="commandText"></param>
/// <param name="commandType"></param>
/// <param name="names"></param>
/// <param name="args"></param>
/// <returns></returns>
private object Execute(string commandText, CommandType commandType, IEnumerable<string> names, object[] args)
{
bool manageConnectionLifespan = (this.Connection.State == ConnectionState.Closed);
if (manageConnectionLifespan) this.Connection.Open();
try
{
using (var cmd = this.Connection.CreateCommand())
{
cmd.CommandType = commandType;
cmd.CommandText = commandText;
for (int i = 0; i < args.Length; i++)
{
DbParameter param = cmd.CreateParameter();
param.ParameterName = "@" + names.ElementAt(i);
param.Value = args[i] == null ? DBNull.Value : args[i];
cmd.Parameters.Add(param);
}
return ExecuteList(cmd);
}
}
finally
{
if (manageConnectionLifespan)
{
this.Connection.Close();
}
}
}
/// <summary>
/// 执行SQL命令,返回查询结果列表
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
private static IEnumerable<dynamic> ExecuteList(DbCommand command)
{
List<DynamicEntity> resultList = new List<DynamicEntity>();
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
DynamicEntity entity = new DynamicEntity();
for (int i = 0; i < reader.FieldCount; i++)
{
entity.SetMember(reader.GetName(i), reader.GetValue(i));
}
resultList.Add(entity);
}
}
return resultList;
}
}
/// <summary>
/// 动态实体
/// </summary>
internal class DynamicEntity : DynamicObject
{
/// <summary>
/// 属性和值的字典表
/// </summary>
private Dictionary<string, object> values = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (values.ContainsKey(binder.Name))
{
result = values[binder.Name];
}
else
{
throw new System.MissingMemberException("The property " + binder.Name + " does not exist");
}
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
SetMember(binder.Name, value);
return true;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return values.Keys;
}
internal void SetMember(string propertyName, object value)
{
if (object.ReferenceEquals(value, DBNull.Value))
{
values[propertyName] = null;
}
else
{
values[propertyName] = value;
}
}
}
要知道 ADO.NET 可不是.NET菜鸟,它看到 command("select Top 10 * from Orders"); 第一感觉认为吃了dynamic药的command有可能是委托类型,而看到后面的 command.CustOrdersOrders(CustomerID: "ALFKI"); 不得不否决了前面的看法。dynamic到底是什么东西?可以这样认为,dynamic什么东西都是;也可以认为,dynamic不是什么东西!
ADO.NET 知道任何.NET写的再高深的代码在reflector下都会现出原形,通过对 command 解剖,立刻明白原来自己跟《美丽心灵》的纳什教授一样纠缠于一种不存在的幻想不能自拔,reflector告诉我们:dynamic实际上是不存在的!
还是鲁迅叔叔说的好,世界上本没有dynamic,只是微软对委托封装得太牛了,也便有了dynamic。
结语
聪明的你知道command是怎么实现了吗?不妨先想想,然后展开下面的代码看看是否与你想的一致。