自从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<T>对象,方法中CloneNavigationProperty是为单个对象赋值,而CloneNavigationPropertyEntityCollection方法是为多个对象赋值。

   public class UpdateHelp:IDisposable    {//记录已经复制过的实体类,避免重复加载        private IList<Type> listType = new List<Type>();private BusinessContext _context;

public UpdateHelp(BusinessContext context)        {            _context = context;        }

public void Dispose()        {            _context.Dispose();        }

//更新普通属性        private void CloneProperty(PropertyInfo propertyInfo,object intrinsicObj,object newObj)        {var data = propertyInfo.GetValue(newObj, null);            propertyInfo.SetValue(intrinsicObj, data, null);        }

//更新普通导航属性        private void CloneNavigationProperty(PropertyInfo propertyInfo,object intrinsicObj,object newObj)        {var data = propertyInfo.GetValue(newObj, null);object dataClone = UpdateIntrinsticObj(data);            propertyInfo.SetValue(intrinsicObj, dataClone, null);        }

//更新返回值为集合EntityCollection<TEntity>的导航属性        private void CloneNavigationPropertyEntityCollection(PropertyInfo propertyInfo, object intrinsicObj, object newObj)        {//获取参数newObj中的对象集合            IEnumerable<object> newData = propertyInfo.GetValue(newObj, null) as IEnumerable<object>;//获取上下文中匹配的原对象集合            var intrinsicData = propertyInfo.GetValue(intrinsicObj, null);//利用EntityCollection<TEntity>类的扩展方法Add在原集合中加入新对象            var addMethod = intrinsicData.GetType().GetMethod("Add");foreach (object obj in newData)            {                Object objClone = UpdateIntrinsticObj(obj);                addMethod.Invoke(intrinsicData, new object[] { objClone });            }        }

//获取上下文中待更新的原对象        private object GetIntrinsicObj(EntityObject entity)        {                        Object intrinsicObj;//根据输入对象的EntityKey判断该对象是已有值还是新建值//若是已有值即从上下文中获取对应值,若是新建值即反射生成一个新对象            if (entity.EntityKey.EntityKeyValues != null)                intrinsicObj = _context.GetObjectByKey(entity.EntityKey);else                intrinsicObj = Activator.CreateInstance(entity.GetType());

return intrinsicObj;        }

//更新上下文中的原对象,返回值为更新后的原对象        public object UpdateIntrinsticObj(Object obj)        {//记录已经复制过的实体类,避免重复加载            listType.Add(obj.GetType());//获取上下文中的原对象            Object intrinsicObj=GetIntrinsicObj(obj as EntityObject);//更新原对象的每个一个属性//把原对象intrinsicObj的每一个属性设置为与obj对象相等            foreach (PropertyInfo propertyInfo in obj.GetType().GetProperties())            {//若listType里面包含些类型,证明此实体类已经更新过                if (!listType.Contains(propertyInfo.PropertyType) && propertyInfo.CanWrite                    && propertyInfo.Name != "EntityKey"&& propertyInfo.PropertyType.Name != "EntityReference`1")                {//若为导航属性则需要使用此方法更新                    if (propertyInfo.GetCustomAttributes(typeof(EdmRelationshipNavigationPropertyAttribute), false).Count() != 0)                    {//若导航属性返回值为集合则使用此方法                        if (propertyInfo.PropertyType.Name == "EntityCollection`1")                            CloneNavigationPropertyEntityCollection(propertyInfo, intrinsicObj, obj);else//若导航属性为普通对象则使用以下方法                            CloneNavigationProperty(propertyInfo, intrinsicObj, obj);                    }else //若为普通属性则使用以下方法                        CloneProperty(propertyInfo, intrinsicObj, obj);                }            }return intrinsicObj;        }    }

在完成更新操作后,再加上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<T>(T entity) where T : EntityObject        {int n = -1;            Transaction transaction = Transaction.Current;try            {                _context.AddObject(entity.GetType().Name, entity);                n = _context.SaveChanges();            }catch (Exception ex)            {                Business.Common.ExceptionManager.DataException.DealWith(ex);                transaction.Rollback();            }return n;        }

public int Update<T>(ref T entity) where T:EntityObject        {int n = -1;            Transaction transaction = Transaction.Current;try            {                EntityObject returnObj = this._updateHelp.UpdateIntrinsticObj(entity) as EntityObject;                n = _context.SaveChanges();                entity = _context.GetObjectByKey(entity.EntityKey) as T;            }catch (Exception ex)            {                Business.Common.ExceptionManager.DataException.DealWith(ex);                transaction.Rollback();            }return n;        }

public List<T> GetList<T>(string name) where T:EntityObject        {......}         ........    }

public class OrderRepository    {private LinqHelp _linqHelp;

public OrderRepository()        {            _linqHelp = new LinqHelp();         }

public int AddOrder(Order order)        {..........}

        ..............

public int UpdateOrder(Order order)        {return _linqHelp.Update<Order>(ref order);        }    }
    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);            }        }    }

四、性能问题

由于过度使用反射会使系统的性能下降,所以需要注意此更新方法的使用范围。一般此反射更新只会使用在小型的项目当中,如果在大中型项目内使用,将会在性能上负出代价。由于时间有限,而且没有经过大量的测试,有不足之处请点评。

对.NET开发有兴趣的朋友请加入博客园讨论小组“.NET高级编程” 一起探讨!

转载于:https://www.cnblogs.com/wangyajun/archive/2012/04/26/2471788.html

利用泛型与反射更新实体(ADO.NET Entity Framework)相关推荐

  1. ADO.NET Entity Framework Beta2(五)/快速入门(实体框架)

    This quickstart illustrates a series of tasks that support the topics in Getting Started with the En ...

  2. 转载:ADO.NET Entity Framework 试水系列索引(2008/9/9更新,本系列结束)

    Visual Studio 2008发布时,微软给我们带来了LinQ to SQL,解决所谓"阻抗不匹配"问题.最近,随着Visual Studio 2008 SP1的正式发布,又 ...

  3. ADO.NET Entity Framework 简介

    一直对EF都是一知半解的,没有系统的了解过EF有什么样的功能,有什么具体的好处.在接下来的文章中会详细介绍EF.以下是参考MSDN上的文章,翻译并加以自己的理解得出的. ADO.NET Entity  ...

  4. ADO.NET Entity Framework 基本概述

    时间过得很快转眼间VS已经2010版了,在4月12日将会正式发布VS 2010 ADOEF 做为.Net 4.0 中被微软推荐的ORM框架,相比.Net 3.5 sp1 已经得到了进一步的增强,使用它 ...

  5. ADO.NET Entity Framework 入门示例向导(附Demo程序下载)

    ADO.NET Entity Framework 入门示例向导(附Demo程序下载) ADO.NET Entity Framework 是.Net Framework 3.5 SP1 引入的实体框架, ...

  6. ADO.NET Entity Framework 深入分析, Part 5

    ADO.NET Entity Framework 深入分析, Part 5 前面的Part 1-4的文章,介绍了Entity Data Model.Entity SQL.ObjectQuery.Ent ...

  7. EF架构~了解一下,ADO.NET Entity Framework

    回到目录 以下文章部分来自百度百科 背景 长久以来,程序设计师和数据库总是保持着一种微妙的关系,在商用应用程序中,数据库一定是不可或缺的元件,这让程序设计师一定要为了连接与访问数据库而去 学习 SQL ...

  8. Entity Framework (EF)/Linq To entity/ ESQL(entity sql)区别 ADO.NET Entity Framework:来自微软官方的ORM框架

    长久以来,程序员和数据库总是保持着一种微妙的关系,在商用应用程序中,数据库一定是不可或缺的元件,这让程序员一定要为了连接与访问数据库而去学习 SQL 指令,至少对于我而言,我觉得这是一个很不爽的事情. ...

  9. 实体框架(Entity Framework)简介

    实体框架(Entity Framework)简介 实体框架(Entity Framework)简介 简称EF,与ADO.NET关系 ADO.NET Entity Framework 是微软以 ADO. ...

最新文章

  1. Xamarin.Android之Fragment Walkthrough
  2. 9.3 域名解析与网页爬虫
  3. 1008 Elevator (20 分)【难度: 简单 / 知识点: 模拟】
  4. 使用 Bamboo 构建项目的 CICD 过程文档
  5. Jquery- 错误消息Date未定义,String未定义
  6. Qt消息机制和事件概述(一)
  7. AJAX,只是一种过渡技术吗?
  8. MFC程序打开文件对话框出错的问题解决
  9. python学习笔记4(对象/引用;多范式; 上下文管理器)
  10. 基于Spring Boot 的Blog开发(一)
  11. mac搜索不到wifi wtg_如何设置隐藏wifi 防止蹭网隐藏wifi方法【详解】
  12. Algs4-1.1.6下面这段程序会打印出什么
  13. python设计模式之MVC
  14. google的视频下载插件
  15. 苹果新专利:紧急情况下可用指纹或特定输入操作悄悄呼救
  16. 职业规划,如何月入1万、3万、5万、10万?
  17. STM32寄存器配置USART1串口及USART->BRR值的计算
  18. Latex编辑数学符号和希腊字母的方法
  19. Python题库——题目
  20. live555源代码分析

热门文章

  1. rman一致性备份oracle数据库可以在非归档模式下么,探索ORACLE之RMAN_03一致性备份...
  2. html5两个静态页面传值,如何使用HTML5Viewer 进行参数传递
  3. php+select为空,SELECT时候,如何处理某字段空值?
  4. python元组是有序还是无序_python-03 元组和字典
  5. grpc python stream_Python gRPC笔记
  6. spark.network.timeout参数入门
  7. GeoHash入门及应用
  8. SparkSession对象
  9. 【转】契约测试的必要性
  10. nginx官方模块之http_random_index_module