.NET基础篇——利用泛型与反射更新实体(ADO.NET Entity Framework)
自从ADO.NET Entity Framework面世以来,受到大家的热捧,它封装了大量代码生成的工具,用户只需要建立好实体之间的关系,系统就是会为用户自动成功了Add、Delete、CreateObject、Attach、ToList......等等方法,这些方法基本上已经包含获取、删除、插入等基本方法,使用起来非常方便。只是在实体的更新上,由于LINQ面向的是泛型对象T,所以每个对象的更新方法都要由用户自动编辑。有见及此,下面在下利用反射方法,创建了一个更新工具,此工具可以更新ObjectContext里面的任意一个实体或者多个关联实体。
自从ADO.NET Entity Framework面世以来,受到大家的热捧,它封装了大量代码生成的工具,用户只需要建立好实体之间的关系,系统就是会为用户自动成功了Add、Delete、CreateObject、Attach、ToList......等等方法,这些方法基本上已经包含获取、删除、插入等基本方法,使用起来非常方便。只是在实体的更新上,由于LINQ面向的是泛型对象T,所以每个对象的更新方法都要由用户自动编辑。有见及此,下面在下利用反射方法,创建了一个更新工具,此工具可以更新ObjectContext里面的任意一个实体或者多个关联实体。
一、简单介绍反射
反射是一个程序集发现及运行的过程,通过反射可以得到*.exe或*.dll等程序 集内部的信息。使用反射可以看到一个程序集内部的接口、类、方法、字段、属性、特性等等信息。在System.Reflection命名空间内包含多个反 射常用的类,下面表格列出了常用的几个类。(详细的资料请参考“反射的奥妙”)
类型 | 作用 |
Assembly | 通过此类可以加载操纵一个程序集,并获取程序集内部信息 |
EventInfo | 该类保存给定的事件信息 |
FieldInfo | 该类保存给定的字段信息 |
MethodInfo | 该类保存给定的方法信息 |
MemberInfo | 该类是一个基类,它定义了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多个公用行为 |
Module | 该类可以使你能访问多个程序集中的给定模块 |
ParameterInfo | 该类保存给定的参数信息 |
PropertyInfo | 该类保存给定的属性信息 |
二 、实体与上下文的关系
每个实体值都会包含在上下文中, 当您从客户端回收到实体时, 可以比较与上下文中的该实体的版本更新的实体,并应用适当的更改。值得注意的是,上下文会必须KEY找到实体对像,然后对每一个属性逐个赋值。如果想对实体对象直接赋值,那么KEY那将会改变,系统将无法从上下文中找到该对象。
三、开发实例
在为一个项目建立关系图时,都会为多个实体建立关系,在更新实体时往往需要把导航属性一同更新,这使得更新方法更为繁琐。比如在觉见的订单管理项目中,在更新订单Order的同时,必须把订单对应的OrderItem对象实现同步更新。为了简化代码,在下利用反射原理建立一个了特定类UpdateHelp,利用这个类可以更新ObjectContext里面的多个关系对象。
其原理在于系统使用GetIntrinsicObj(EntityObject)方法,根据输入实体(obj)的KEY在上下文中获取对应的实体对象(intrinsic),然后使用UpdateIntrinsticObj(Object)方法,利用PropertyInfo遍历实体的每个属性,把输入的实体对象(obj)的每个属性都赋值给上下文的实体对象(intrinsic)。最特别的地方在于当遇到导航属性的时候,使用了递归算法,重复调用UpdateIntrinsticObj(object)方法为导航属性赋值。当遇到一对多或者多对多关系的时候,导航属性将会是是一个List
public class UpdateHelp:IDisposable { //记录已经复制过的实体类,避免重复加载 private IList
在完成更新操作后,再加上LingHelp类,就可以利用它完成大部的数据处理问题,大家可以建立main测试一下。
public class LinqHelp:IDisposable { private BusinessContext _context; private UpdateHelp _updateHelp; public LinqHelp() { _context = new BusinessContext(); _updateHelp = new UpdateHelp(_context); } public LinqHelp(BusinessContext context) { _context = context; _updateHelp = new UpdateHelp(context); } public void Dispose() { _context.Dispose(); } public int Add
public class PersonRepository {......} class Program { static void Main(string[] args) { Test1(); Console.ReadKey(); } public static void Test1() { using (BusinessContext context = new BusinessContext()) { context.ContextOptions.LazyLoadingEnabled = true; var order = context.Order.First(); order.Person.Address = "北京路1号"; OrderRepository orderRepository = new OrderRepository(); orderRepository.UpdateOrder(order); } } public static void Test2() { using (BusinessContext context = new BusinessContext()) { Person person = context.Person.First(); Order order = new Order(); order.OrderNumber = "2A34313344"; OrderItem orderItem = new OrderItem(); orderItem.Goods = "555"; orderItem.Count = 8; orderItem.Price = 2.5; order.OrderItem.Add(orderItem); person.Order.Add(order); PersonRepository personRepository = new PersonRepository(); personRepository.UpdatePerson(person); Console.Write(person.Order.First().ID + person.Order.First().OrderItem.First().ID); } } }
四、性能问题
由于过度使用反射会使系统的性能下降,所以需要注意此更新方法的使用范围。一般此反射更新只会使用在小型的项目当中,如果在大中型项目内使用,将会在性能上负出代价。由于时间有限,而且没有经过大量的测试,有不足之处请点评。