LINQ To SQL和ORM的理解浅析

开发 后端
LINQ To SQL和ORM的理解是如何的呢?我们在学习LINQ To SQL以及ORM的时候应该注意什么呢?那么本文就向你介绍一些自己的学习体会,希望对你有所帮助。

LINQ To SQL和ORM的理解是什么呢,这将会是我们掌握LINQ技术的关键,那么对于LINQ To SQL具体的是什么含义,那么操作我们是需要明确的呢?那么下面我们就向你讲述一下关于LINQ To SQL和ORM的相关理解。

有N个用LINQ的理由,也有N个不用LINQ的理由。在完善框架的时候,电信的一位技术总监跟我说:我不建议你做框架,那是微软等大公司的事,我们主要是用框架,你现在写ORM,现在的DotNet3.5 已经处于Alpha测试阶段了,你的ORM还有多大的用处。我当时一下子迷惘了,赶快找资料,从Lamda表达式开始学起,对于我来说难度还是不少的(是在考验我的数学呀)。最终还是放弃了。

LINQ To SQL和ORM的理解1、

没有LINQ的源代码,不知道清楚中间的数据是如何处理的,特别是缓存是如何处理的。

LINQ To SQL和ORM的理解2、

用LINQ翻译到存储过程/Sql语句效率很低的,对于复杂的对效率有一定的要求的,还是要写存储过程。而且翻译出来的存储过程/Sql语句的怎么缓存,第二次执行的时候还要重新翻译,不能很好的利用缓存。

LINQ To SQL和ORM的理解3、工具的支持。

这一点是非常重要。如果没有有力工具的支持,用ORM简直就是恶梦。LINQ的工具支持总的来说,现在在VS2008里的支持我感觉还不是很友好。至少有一点,我们通常在表的备注里面写下这个字段的注释,很多情况下对应到界面上就是这个字段的抬头,这个工具不能直接生成到项目里去,因为我们不能控制,再者,现在的项目都不是由一个人完成,如果一个类有几十个字段,很难记住解释,自己的工具可以加入注释,方便开发。

LINQ To SQL和ORM的理解4、与业务层的综合。

通常ORM映射就是把对象与关系表之间形成映射关系,映射的目标是为了方便业务层的逻辑处理,如果不能与业务层无缝的结合起来,那么对于项目的开发,也未必有多少好处。至少在的ORM里面,与的我业务层可以非常友好的集成在一起。

LINQ To SQL和ORM的理解5、多数据源的支持。

对于我来说,这点也是非常关键的。我说的多数据源是指一个项目里面,有多个数据库,比如:基础数据、客户管理、业务运作、权限管理等,这些都是相对独立的模块,开发的时候,可以把这几个作为单独的项目开发,各自有自己独立的数据库,而且在多个项目里面,这些模块都是非常相似,像权限模块基本上是通用的,没有必要再重复开发。如果能够做到数据库层分离,则新项目开发的时候,可以达到更快的速度。当然也可以做到很容易的分合,把两个数据库合并成一个,或者把一个数据库分开成两个,只涉及到配置文件的更改,在开发的时候可以不关心的。

LINQ To SQL和ORM的理解6、对于可变查询的处理。

也就是相当于拼接字符串了。可能会说,这个是LINQ的强项,但是,如果对于一个分布式的项目呢?又应该如何处理。知道ORM的朋友应该都知道IBatis.net 和NHibnate ,I家的参数处理是非常的方便的,N家呢就没有I的直观,但是对于面向对象的处理I比N家好像就有太多的不足了。对于远程处理要能够通过参数传递这些只对映射层公开的参数,这点对于程序的某些地方可能是至关重要的影响。我的ORM里面,随便起了一个名字,叫通用查询,业务逻辑里用的查询通常会写在存储过程里,可以通过工具直接生成业务层代码里的函数。

LINQ To SQL和ORM的理解7、对于泛形、继承的支持与处理。

泛形,可以减少很多代码,同时,还可以减少很多人为的错误。

因为人的精力总是有限的,你把精力花在一个地方,那么其他方面肯定关注的少了,我也一样。可能是我把精力过多的放在我的ORM里面,忽略了其他的方面,请大家能够给出批评指正。接下来,把我的ORM映射部分做一详细的介绍

LINQ To SQL和ORM的理解之ORM映射主要分为以下几个方面:

LINQ To SQL和ORM的理解1、对象、参数翻译

a)LINQ To SQL和ORM的理解之对象的表达。对象的映射,我采用的是自定义属性方法。

  1. namespace LG.Common.Enities  
  2. {  
  3. using System;  
  4. using System.Collections.Generic;  
  5. using System.Text;  
  6. using System.Data;  
  7. using System.Data.SqlClient;  
  8. using Unie2e.Common;  
  9. using Unie2e.ORM;  
  10. using Unie2e.ORM.Mapping;  
  11. [System.SerializableAttribute()]  
  12. [Unie2e.ORM.Mapping.TableAttribute(  
  13. "City", MapFileName="CityCustParam.Xml")]  
  14. public sealed class CityEntity :   
  15. Unie2e.ORM.Mapping.Entity  
  16. {  
  17. /**//// <summary>  
  18. /// 映射字段的总长度  
  19. /// </summary>  
  20. private const int length = 5; 
#p#

LINQ To SQL和ORM的理解之映射字段

  1. #region 映射字段  
  2.  
  3. /**//// <summary>  
  4.  
  5. /// 城市Id  
  6.  
  7. /// </summary>  
  8.  
  9. [Unie2e.ORM.Mapping.FieldAttribute(  
  10. "City""CityId"true, SqlDbType.  
  11. UniqueIdentifier, 0, 0, 0, "城市Id")]  
  12.  
  13. public Guid CityId = System.Guid.NewGuid();  
  14.  
  15. /**//// <summary>  
  16.  
  17. /// 省份Id  
  18.  
  19. /// </summary>  
  20.  
  21. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  22. "ProvinceId"false, SqlDbType.UniqueIdentifier,  
  23.  0, 0, 0, "省份Id")]  
  24.  
  25. public Guid ProvinceId = System.Guid.Empty;  
  26.  
  27. /**//// <summary>  
  28.  
  29. /// 城市代码  
  30.  
  31. /// </summary>  
  32.  
  33. [Unie2e.ORM.Mapping.FieldAttribute("City",  
  34. "CityCode"false, SqlDbType.VarChar,  
  35.  50, 0, 0, "城市代码")]  
  36.  
  37. public String CityCode;  
  38.  
  39. /**//// <summary>  
  40.  
  41. /// 城市名称  
  42.  
  43. /// </summary>  
  44.  
  45. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  46. "CityName"false, SqlDbType.VarChar,   
  47. 50, 0, 0, "城市名称")]  
  48.  
  49. public String CityName;  
  50.  
  51. /**//// <summary>  
  52.  
  53. /// 备注  
  54.  
  55. /// </summary>  
  56.  
  57. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  58. "CityComment"false, SqlDbType.VarChar,   
  59. 200, 0, 0, "备注")]  
  60.  
  61. public String CityComment;  
  62.  
  63. #endregion  

LINQ To SQL和ORM的理解之重载基类函数

  1. public override void Initialize(object[] parameters)  
  2.  
  3. {  
  4.  
  5. if ((length != parameters.Length))  
  6. {  
  7. throw new E2EException("参数个数与字段数不相等");  
  8. }  
  9. CityId = ((System.Guid)(parameters[0]));  
  10. ProvinceId = ((System.Guid)(parameters[1]));  
  11. CityCode = ((string)(parameters[2]));  
  12. CityName = ((string)(parameters[3]));  
  13. CityComment = ((string)(parameters[4]));  
  14. }  
  15. public override object[] ToArray()  
  16. {  
  17. object[] objs = new object[5];  
  18. objs[0] = CityId;  
  19. objs[1] = ProvinceId;  
  20. objs[2] = CityCode;  
  21. objs[3] = CityName;  
  22. objs[4] = CityComment;  
  23. return objs;  
  24. }  
  25. #endregion  
  26. }  
  27. [System.SerializableAttribute()]  
  28. [Unie2e.ORM.Mapping.TableAttribute("City")]  
  29. public abstract class CityFindParam<T> : EntityParam<T> where T: IEntity  
  30. {  
  31. /**//// <summary>  
  32.  
  33. /// 映射字段的总长度  
  34. /// </summary>  
  35. private const int length = 6;  

LINQ To SQL和ORM的理解之映射字段

  1. [Unie2e.ORM.Mapping.FieldAttribute(  
  2. "City""Method", SqlDbType.VarChar, 50, 0, 0, "")]  
  3.  
  4. public String Method;  
  5.  
  6. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  7. "CityId", SqlDbType.UniqueIdentifier, 0, 0, 0, "")]  
  8.  
  9. public Guid CityId = System.Guid.Empty;  
  10.  
  11. [Unie2e.ORM.Mapping.FieldAttribute("City",  
  12.  "ProvinceId", SqlDbType.UniqueIdentifier, 0, 0, 0, "")]  
  13.  
  14. public Guid ProvinceId = System.Guid.Empty;  
  15.  
  16. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  17. "CityCode", SqlDbType.VarChar, 50, 0, 0, "")]  
  18.  
  19. public String CityCode;  
  20.  
  21. [Unie2e.ORM.Mapping.FieldAttribute("City",  
  22.  "CityName", SqlDbType.VarChar, 50, 0, 0, "")]  
  23.  
  24. public String CityName;  
  25.  
  26. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  27. "CityComment", SqlDbType.VarChar, 200, 0, 0, "")]  
  28.  
  29. public String CityComment;  
  30.  
  31. #endregion  

LINQ To SQL和ORM的理解之重载基类函数

  1. public override object[] ToArray()  
  2. {  
  3. object[] objs = new object[6];  
  4. objs[0] = Method;  
  5. objs[1] = CityId;  
  6. objs[2] = ProvinceId;  
  7. objs[3] = CityCode;  
  8. objs[4] = CityName;  
  9. objs[5] = CityComment;  
  10. return objs;  
  11. }  
  12. public override void Initialize(object[] parameters)  
  13. {  
  14. if ((length != parameters.Length))  
  15. {  
  16. throw new E2EException("参数个数与字段数不相等");  
  17. }  
  18. Method = ((String)(parameters[0]));  
  19. CityId = ((Guid)(parameters[1]));  
  20. ProvinceId = ((Guid)(parameters[2]));  
  21. CityCode = ((String)(parameters[3]));  
  22. CityName = ((String)(parameters[4]));  
  23. CityComment = ((String)(parameters[5]));  
  24. }  
  25. #endregion  
  26. }  
  27. [System.SerializableAttribute()]  
  28. [Unie2e.ORM.Mapping.TableAttribute("City")]  
  29. public sealed class CityFindParam : CityFindParam<CityEntity>  
  30. {  
  31. }  
  32. [System.SerializableAttribute()]  
  33. [Unie2e.ORM.Mapping.TableAttribute("City")]  
  34. public abstract class CityActionParam<T> :   
  35. EntityParam<T> where T: IEntity  
  36.  
  37. {  
  38.  
  39. /**//// <summary>  
  40. /// 映射字段的总长度  
  41. /// </summary>  
  42. private const int length = 2;  
  43. 映射字段#region 映射字段  
  44. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  45. "Method", SqlDbType.VarChar, 50, 0, 0, "")]  
  46. public String Method;  
  47. [Unie2e.ORM.Mapping.FieldAttribute("City",   
  48. "CityId", SqlDbType.UniqueIdentifier, 0, 0, 0, "")]  
  49. public Guid CityId = System.Guid.Empty;  
  50. #endregion  

#p#

LINQ To SQL和ORM的理解之重载基类函数

  1. public override object[] ToArray()  
  2. {  
  3. object[] objs = new object[2];  
  4. objs[0] = Method;  
  5. objs[1] = CityId;  
  6. return objs;  
  7. }  
  8. public override void Initialize(object[] parameters)  
  9. {  
  10. if ((length != parameters.Length))  
  11. {  
  12. throw new E2EException("参数个数与字段数不相等");  
  13. }  
  14. Method = ((String)(parameters[0]));  
  15. CityId = ((Guid)(parameters[1]));  
  16. }  
  17. #endregion  
  18. }  
  19.  
  20. [System.SerializableAttribute()]  
  21. [Unie2e.ORM.Mapping.TableAttribute("City")]  
  22. public sealed class CityActionParam :   
  23. CityActionParam<CityEntity>  
  24. {  
  25. }  
  26. }  
  27.  
  28. [Unie2e.ORM.Mapping.TableAttribute("City",   
  29. MapFileName="CityCustParam.Xml")]  

给出了映射对象与数据库表或者视图的关系,MapFileName给出了所对应的通用查询的配置文件,当然也可以把Sql语句写在配置文件里面,实现查询之外的其他动作处理。因为工具没有对其他生成代码函数的支持,所以通常还是通过工具来生成存储过程来处理。

在Entity里面,有两上重载的函数:public override void Initialize(object[] parameters)和public override object[] ToArray(),这两个函数是为了加速数据加载的。底层用的是DataReader读取数据,尽可能少的通过反射加载数据,实现数据的快速从数据库加载到对象里面,因为这些代码都是通过工具生成的,不会出现错误,比较要注意的是用工具写存储过程的时候要注意一点就可以了。

  1. [Unie2e.ORM.Mapping.FieldAttribute("City""CityId",   
  2.  
  3. true, SqlDbType.UniqueIdentifier, 0, 0, 0, "城市Id")]  

给出了对象Field与表或视图的列的映射关系。***一个是对于注释,对于BO的业务数据会生成Summary。最终会生成到界面的表述,以及列表的配置文件的头。

除了Entity 外,还有CityFindParam<T> ,CityFindParam,CityActionParam<T>,CityActionParam这几个类,CityFindParam<T> 主要是为了实现可变返回数据,默认情况下返回的是完整表的数据,有时候,数据库表或视图的字段很多,比较重要的地方,可能只会要求返回其中的部分字段,用在这方面处理。CityActionParam,主要是针对批量更新等特殊处理,对个别地方进行性能优化处理。

b)LINQ To SQL和ORM的理解之对象翻译

对象翻译就是把对象属性翻译到成相对应的存储过程的调用。我的ORM映射主要是对象参数处理。添加、删除、修改都是对完整的对象的映射,对于特别的处理是通过Action处理的。

  1. SqlParameter[] BuilderSqlParameters(Type type,SQLActionType actionType)  
  2. {  
  3. FieldInfo[] infos = type.GetFields();  
  4. SqlParameter[] parameters =   
  5. new SqlParameter[infos.Length];  
  6. for (int i = 0; i < infos.Length; i++)  
  7. {  
  8. object[] objs = infos[i].GetCustomAttributes(typeof(FieldAttribute), false);  
  9. FieldAttribute attr = objs[0] as FieldAttribute;  
  10. SqlParameter sp;  
  11. if (attr.Length != 0)  
  12. sp = new SqlParameter("@" + attr.ColumnName, attr.SqlDbType, attr.Length);  
  13. else 
  14.  {  
  15.  sp = new SqlParameter("@" + attr.ColumnName, attr.SqlDbType);  
  16.  }  
  17.  if (attr.IsKey&&actionType== SQLActionType .Insert)  
  18.  sp.Direction = ParameterDirection.InputOutput;  
  19.  parameters[i]=sp;  
  20. }  
  21. }  
  22. return parameters;  

***次执行的时候,遍历所有字段,根据FieldAttribute 生成调用存储过程的Command,并缓存,第二次执行的时候,直接从缓存里取出Command 的Clone()。此处调用Clone ,返回的是Command的DeepCopy!!!也是微软在2.0里面新添加的函数,我估计新加的函数的用处也就是在这里了,极大的提高了处理速度。接下来就是存储过程的赋值了。

  1. void AssignParameterValues(object instance, SqlCommand cmd)  
  2. {  
  3. SqlParameterCollection sps = cmd.Parameters;  
  4. IEntity idb =instance as IEntity;  
  5. if (idb == null)  
  6. throw new Exception("存储过程赋值出错,要具有IEntity接口");  
  7. object[] values = idb.ToArray();  
  8. if (values.Length != sps.Count )  
  9. throw new Exception("参数个数不一致");  
  10. for (int i = 0; i < values.Length; i++)  
  11. {  
  12. object val = values[i];  
  13. //对于时间的空值等,这里还会报错。一般要求要有初始化。  
  14. sps[i].Value =null == val ?System.DBNull.Value:val;  
  15. }  

刚刚介绍了在Entity和ParamEntity里面有两个重载的虚函数函数,其中一个是:ToArray(),在这里用到了。如果是通过反射得到实例的值,那效率实在是太低了,这里用了IEntity的ToArray(),因为映射的顺序位置都是固定的,所以可以通过数组的方式实现。这也是工具的重要的地方,靠手工处理,错误的几率太高了。

现在存储过程是可以正常调用了,正常的 增、改、删,是可以处理了,下面介绍取数据。

#p#

c)LINQ To SQL和ORM的理解之数据读取加载

数据加载主要是通过DataReader实现的。

  1. object GetFindResult(IDataReader reader, Type targetType)  
  2. {  
  3. Type target = targetType;  
  4. object[] fields = new object[reader.FieldCount];  
  5. IEntity t = (IEntity)Activator.CreateInstance(target);  
  6. Type constructed = typeof(ORMCollection<>).  
  7. MakeGenericType(target);  
  8. IList list = (IList)Activator.CreateInstance(constructed);  
  9. while (reader.Read())  
  10. {  
  11. for (int i = 0; i < fields.Length; i++)  
  12. {  
  13.  fields[i] = reader.IsDBNull(i) ? null : reader[i];  
  14. }  
  15. t.Initialize(fields);  
  16. list.Add(t.Clone());  
  17. }  
  18. return list;  
  19. }  
  20. object GetFindResult(IDataReader reader,  
  21.  Type targetType, int currentpage, int pagesize) 

数据加载提供了2个函数,一个是带分页一个是不带分页。IEntity提供的几个接口在这里都用了,也主要是为了这里准备的。也主要是在此实现了数据的快速加载。主要体现在两个上面,一个是t.Initialize(fields),Initialize 在上面是介绍了,不用通过反射初始化及赋值,再者是 t.Clone(),用的也是DeepCopy,不是用Activator 创建新的对象实例,因为Activator 构造对象的时候速度跟DeepCopy相比,要慢了很多。

还有一个是我自封的通用查询,也就是通过MapFileName 找到配置文件,把Sql配置文件加载进来,翻译成Command加到缓存里面,后期的处理与上面的一样,在这里就不再过多的介绍了,只把关键代码列出来。

  1. string BuildFind(FieldInfo[] pis, FinderParam finderParam,  
  2.  out SqlParameter[] parameters)  
  3. {  
  4. ORMCollection<FinderParamItem> items =   
  5. finderParam.ParamItemCollection;  
  6. if (items==null)  
  7.  
  8. throw new E2EException("ParamItemCollection参数不能为空");  
  9. StringBuilder sb = new StringBuilder();  
  10. List<SqlParameter> parameterList = new List<SqlParameter>();  
  11. foreach (FinderParamItem var in items)  
  12. {  
  13. FieldInfo pi = Array.Find(pis, delegate(FieldInfo obj) {   
  14. return obj.Name.Equals(var.PropertyName,  
  15.  StringComparison.OrdinalIgnoreCase); });  
  16.  
  17. if (pi == null)  
  18.  
  19.  throw new E2EException("不存在参数:"+var.PropertyName);   
  20.  
  21. object[] attribs = pi.GetCustomAttributes(  
  22. typeof(FieldAttribute), false);  
  23.  
  24. if (attribs.Length == 0)  
  25. continue;  
  26. FieldAttribute attr = attribs[0] as FieldAttribute;  
  27. string typeName = pi.FieldType.Name;  
  28. if (sb.Length != 0)  
  29. {  
  30. switch (var.JoinKey)  
  31. {  
  32. case JoinKey.与:  
  33.  sb.Append(" AND ");  
  34.  break;  
  35.  case JoinKey.或:  
  36.  sb.Append(" OR ");  
  37.  break;  
  38.  default:  
  39.  break;  
  40.  }  
  41. }  
  42. sb.Append(" (");  
  43.  
  44. sb.Append(attr.TableName+"."+attr.ColumnName);  
  45.  
  46. switch (var.ComparisonKey)  
  47.  
  48. {  
  49.  case ComparisonKey.等于:  
  50.  sb.Append("=");  
  51.  break;  
  52.  case ComparisonKey.不等于:  
  53.  sb.Append("<>");  
  54.  break;  
  55.  case ComparisonKey.大于:  
  56.  sb.Append(">");  
  57.  break;  
  58.  case ComparisonKey.小于:  
  59.  sb.Append("<");  
  60.  break;  
  61.  case ComparisonKey.大于等于:  
  62.  sb.Append(">=");  
  63.  break;  
  64.  case ComparisonKey.小于等于:  
  65.  sb.Append("<=");  
  66.  break;  
  67.  case ComparisonKey.包含:  
  68.  sb.Append(" like ");  
  69.  break;  
  70.  case ComparisonKey.不含:  
  71.  sb.Append("<>");  
  72.  break;  
  73.  default:  
  74.  break;  
  75. }  
  76.  
  77. sb.Append("@" + pi.Name + ")");  
  78. SqlParameter param = new SqlParameter();  
  79. param.ParameterName = "@" + pi.Name;  
  80. param.SqlDbType = attr.SqlDbType;  
  81. param.Size = attr.Length;  
  82. param.Scale = (byte)attr.XScale;  
  83. param.Precision = (byte)attr.XPrec;  
  84. param.IsNullable = true;  
  85. parameterList.Add(param);  
  86. sb.Append(" ");  
  87. }  
  88. if (sb.Length > 0)  
  89. sb.Insert(0, " WHERE ");  
  90. parameters = parameterList.ToArray();  
  91. return sb.ToString();  
  92. }  

到此,基本ORM 映射的处理已经介绍完了,映射的代码都是通过工具生成的,不用人工去处理,曾考虑直接生成Dll的,包括存储过程,都是工具与之配套的,至少不用写千篇一率的Insert、Update、Delete、FindById这些枯燥的存储过程了,如果是通过外键关联的,相关的存储过程也是自动生成的,尽可能减少人工处理过程。(建立的时候可以把外键全部进来,代码生成完之后,再把外键去掉,偷工减料的做法,偶经常做 ^_^)

当然,这里只是ORM 处理,还没有把业务逻辑层关联起来,大家最关注的还是业务逻辑处理,这才是核心,我只所以不想更换ORM,部分是由于我的逻辑层的组织。

原文来自:http://www.cnblogs.com/dreamstec/archive/2008/02/06/1065343.html

关于LINQ To SQL和ORM的理解的相关内容就向你介绍到这里,希望对你了解和学习LINQ To SQL和ORM的理解有所帮助。

【编辑推荐】

  1. LINQ删除记录实战解析
  2. 浅析LINQ嵌套的实现过程
  3. LINQ嵌套实战案例分析
  4. LINQ模糊查询应用实例分析
  5. LINQ模糊查询学习体验浅析
责任编辑:仲衡 来源: 博客园
相关推荐

2009-09-17 17:34:23

linq to sql

2009-09-10 18:02:23

LINQ to SQL

2009-09-16 17:11:35

LINQ To SQL

2009-09-17 18:05:15

linq to sql

2009-09-15 10:12:37

LINQ To SQL

2009-09-14 09:46:00

LINQ to SQL

2009-09-10 10:09:46

LINQ to SQL

2009-09-14 14:20:36

LINQ ORM

2009-09-18 14:25:36

LINQ to SQL

2009-09-14 19:20:22

LINQ TO SQL

2009-09-15 14:30:11

Linq连接

2009-06-15 17:32:09

LINQ更新数据

2009-09-18 14:33:37

LINQ to SQLSQL命令

2009-09-14 18:57:19

LINQ查询

2009-09-22 13:09:06

Hibernateorm框架

2009-09-17 13:30:32

LINQ to XML

2009-09-14 16:46:15

LINQ to XML

2009-09-16 15:33:22

LINQ to XML

2009-09-15 13:30:54

linq级联

2009-09-07 16:44:28

Linq String
点赞
收藏

51CTO技术栈公众号