dynamic遇上ADO.NET
传说中的dynamic
dynamic是个不合群、不按规则办事的家伙,可以说是个异形,但更恐怖的是它又是无所不知的,任何事情都难不了它(咳咳,它似乎与Lambda表达式是死对头)。这令人想起《死亡日记》的怪异侦探L,行为怪异而智力超人,以至于离奇的案件不得不交给了他。dynamic可以看成是一切类型的化身,但并不是仅限于此,它像《未来战士》续集里面的T-1000型液体金属的终结者。噢~~~~似乎扯的有点远了
饱经风雨而不倒的ADO.NET
ADO.NET 从来做事都有理有据,而且又异常专注于自身领域,是个professional的牛人,令人想起《美丽心灵》里面的博弈论和微分几何学领域潜心研究以致获得诺贝尔经济学奖的数学家—— 约翰·福布斯·纳什 教授(咳咳,纳什教授是个妄想型精神分裂的~~~嗯,这个以后再说)。
关于ADO.NET 的例子
1. 执行SQL语句
using (DbCommand command = connection.CreateCommand()) { command.CommandText = "select Top 10 * from Orders"; command.CommandType = CommandType.Text; using (IDataReader reader = command.ExecuteReader()) { while (reader.Read()) { Console.WriteLine("OrderID: {0}, OrderDate: {1}", reader.GetInt32(reader.GetOrdinal("OrderID")), reader.GetDateTime(reader.GetOrdinal("OrderDate"))); } } }
2. 调用存储过程
command.CommandText = "CustOrdersOrders"; command.CommandType = CommandType.StoredProcedure; command.Parameters.Add(new SqlParameter("CustomerID", "ALFKI")); //略去...
当 ADO.NET 遇上 dynamic
某年某月ADO.NET不幸遇到dynamic,从此循规蹈矩的生活不复存在。dynamic说它可以帮助 ADO.NET 丢掉 DataSet 的包袱,而且在不用创建数据实体的情况下,实现查询结果垮不同方法传递;更加强大的地方是可以与存储过程无缝连接,即像调用一般方法一样调用存储过程而不用写额外代码。我的神哪~~~ ADO.NET 听了dynamic一番游说后,心底下不禁惊讶一下。dynamic又说,实现刚才所说的工程只要借你手下的两大猛将 SqlConnection 和 SqlCommand 助我一臂之力即可。
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; } } }
作者:Bruce(编程的艺术世界)
出处:http://coolcode.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。