`
javababy1
  • 浏览: 1229446 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Batch Updating in Entity Framework

阅读更多
Batch Updating in Entity Framework
/黃忠成
The Update Story of Entity Framework
多數的O/R Mapping Framework都有個共同的行為模式,在刪除資料或是修改資料前,必須隱式的下達一個Query,由資料庫取得即將要更新的資料列,
然後轉成物件後再更新。
這個行為模式,多半也會成為設計師考慮是否使用O/R Mapping Framework的考量之一,因為多一個Query,就代表著效能會因此降低,雖然對於
O/R Mapping Framework而言,這是一個必要的行為模式,因為它們得考量到當物件有著關聯時的情況。但對於實際的專案來說,跳過這個Query來更新資料,
卻也是必然會出現的情況,既然是必然會出現的情況,多數的O/R Mapping Framework也只好為此做出讓步,提供可跳過Query來更新資料的機制,
Entity Framework自然也擁有這個機制。
Update Row without Query
Entity Framework支援跳過Query步驟來更新資料列,寫法如下:
static void UpdateWithoutQuery()
{
NorthwindEntities context = new NorthwindEntities();
Customers c = new Customers();
c.CustomerID = "VINET";
context.AttachTo("Customers", c);
c.CompanyName = "15556";
context.SaveChanges();
}
注意,AttachTo的位置很重要,在這之前所設定的值,都不會被寫入,例如下列的Region便不會被寫入。
static void UpdateWithoutQuery()
{
NorthwindEntities context = new NorthwindEntities();
Customers c = new Customers();
c.CustomerID = "VINET";
c.Region = "TWN";
context.AttachTo("Customers", c);
c.CompanyName = "15556";
context.SaveChanges();
}
Delete Row without Query
同樣的手法,也可以用在刪除資料列上。
static void DeleteWithoutQuery()
{
NorthwindEntities context = new NorthwindEntities();
Customers c = new Customers();
c.CustomerID = "CT002";
context.AttachTo("Customers", c);
context.DeleteObject(c);
context.SaveChanges();
}
缺點?
那麼這樣就夠了嗎?事實上,O/R Mapping Framework一直都缺少著一種機制,那就是Batch Update,在很多情況下,我們希望能
下達下列的指令來更新一筆以上的資料列。
UPDATE Customers SET SomeFlag = 1 WHERE Region = “TW”
O/R Mapping Framework中,這得以迴圈方式,一一查詢出每一筆Region=”TW”的資料,然後更新SomeFlag,由於沒有指定主鍵,
所以也無法使用先前提及的方法來跳過Query動作,我們得遵守O/R Mapping Framework的規則,一筆筆Query後更新,這是很沒效率的動作。
當然,所有O/R Mapping Framework都支援讓設計師直接下達SQL的方法,以Entity Framework而言,可以這麼下:
context.ExecuteStoreCommand(“UPDATE Customers SET SomeFlag = 1 WHERE Region = ‘TW’);
不過,這種方法會失去Entity Framework可切換資料庫的特色,所以得特別小心把這部份獨立出來,為日後切換資料庫時留條後路。
Batch Update
那麼,有沒有一個方法,可以達到Batch Update,又不失去Entity Framework可切換資料庫的特色呢?答案是有,下列的類別可以辦到。
001 using System;
002 using System.Collections.Generic;
003 using System.Linq;
004 using System.Text;
005 using System.Data.Objects;
006 using System.ComponentModel;
007 using System.Data.Common;
008 using System.Data;
009 using System.Data.EntityClient;
010 using System.Data.Objects.DataClasses;
011 using System.Reflection;
012 using System.Collections;
013
014
015 namespace EntityHelper
016 {
017 public class EntityBatchUpdater<T>:IDisposable where T :ObjectContext
018 {
019 private static Assembly _systemDataEntity = null;
020 private static Type _propagatorResultType = null;
021 private static Type _entityAdapterType = null;
022 private static Type _updateTranslatorType = null;
023 private static Type _entityStateType = null;
024
025 static EntityBatchUpdater()
026 {
027 _systemDataEntity = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.GetName().Name == "System.Data.Entity").FirstOrDefault();
028 Type t = _systemDataEntity.GetType("System.Data.Mapping.Update.Internal.PropagatorResult");
029 Type t1 = typeof(KeyValuePair<,>).MakeGenericType(t, typeof(object));
030 Type t2 = typeof(List<>).MakeGenericType(t1);
031 _entityAdapterType = _systemDataEntity.GetType("System.Data.IEntityAdapter");
032 _updateTranslatorType = _systemDataEntity.GetType("System.Data.Mapping.Update.Internal.UpdateTranslator");
033 _entityStateType = _systemDataEntity.GetType("System.Data.IEntityStateManager");
034 _propagatorResultType = t2;
035 }
036
037 private T _context = null;
038
039 public T ObjectContext
040 {
041 get
042 {
043 return _context;
044 }
045 }
046
047 public EntityBatchUpdater()
048 {
049 _context = (T)typeof(T).GetConstructor(new Type[]{}).Invoke(new object[]{});
050 }
051
052 static object CreatePropagatorResultDictionary()
053 {
054 return Activator.CreateInstance(_propagatorResultType);
055 }
056
057 static object GetEntityAdapter(ObjectContext context)
058 {
059 object providerFactory = typeof(EntityConnection).GetProperty("ProviderFactory",
060 BindingFlags.NonPublic | BindingFlags.Instance).GetValue(context.Connection, null);
061 object result = ((IServiceProvider)providerFactory).GetService(_entityAdapterType);
062 return result;
063 }
064
065 static object CreateUpdateTranslator(object entityStateManager, System.Data.Metadata.Edm.MetadataWorkspace workspace, EntityConnection connection, int? commandTimeout)
066 {
067 ConstructorInfo ci = _updateTranslatorType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null,
068 new Type[] { _entityStateType, typeof(System.Data.Metadata.Edm.MetadataWorkspace), typeof(EntityConnection), typeof(int?) }, null);
069 return ci.Invoke(new object[] { entityStateManager, workspace, connection, commandTimeout });
070 }
071
072 static string GetQueryStatement(ObjectQuery query)
073 {
074 object queryState = typeof(ObjectQuery).GetProperty("QueryState", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(query, null);
075 object queryPlan = queryState.GetType().BaseType.InvokeMember("GetExecutionPlan", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
076 null, queryState, new object[] { null });
077 DbCommandDefinition cmddef = (DbCommandDefinition)queryPlan.GetType().GetField("CommandDefinition", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(queryPlan);
078
079
080 IEnumerable<string> cmds = (IEnumerable<string>)cmddef.GetType().GetProperty("MappedCommands", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(cmddef, null);
081 return cmds.FirstOrDefault();
082 }
083
084 public static void Update(ObjectContext context)
085 {
086 object entityAdapter = GetEntityAdapter(context);
087 object updateTranslator = CreateUpdateTranslator(context.ObjectStateManager, ((EntityConnection)context.Connection).GetMetadataWorkspace(), (EntityConnection)context.Connection, context.CommandTimeout);
088 IEnumerable o = (IEnumerable)updateTranslator.GetType().InvokeMember("ProduceCommands",
089 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, updateTranslator, null);
090 Dictionary<int, object> identifierValues = new Dictionary<int, object>();
091 object generateValues = CreatePropagatorResultDictionary();
092 context.Connection.Open();
093 try
094 {
095 foreach (var item in o)
096 {
097 item.GetType().InvokeMember("Execute", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, item,
098 new object[] { updateTranslator, (EntityConnection)context.Connection, identifierValues, generateValues });
099 }
100 }
101 finally
102 {
103 context.Connection.Close();
104 }
105 }
106
107 private static void MarkModifiedProperty(ObjectContext context, object entity, params string[] propertys)
108 {
109 context.ObjectStateManager.ChangeObjectState(entity, EntityState.Unchanged);
110 ObjectStateEntry objectStateEntry = context.ObjectStateManager.GetObjectStateEntry(entity);
111 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entity.GetType());
112 foreach (FieldMetadata metadata in objectStateEntry.CurrentValues.DataRecordInfo.FieldMetadata)
113 {
114 string name = objectStateEntry.CurrentValues.GetName(metadata.Ordinal);
115 PropertyDescriptor descriptor = properties[name];
116 if (propertys.Contains(descriptor.Name))
117 objectStateEntry.SetModifiedProperty(descriptor.Name);
118 }
119 }
120
121 public static void UpdateDirect(ObjectContext context, string orKeyFields)
122 {
123 object entityAdapter = GetEntityAdapter(context);
124 object updateTranslator = CreateUpdateTranslator(context.ObjectStateManager, ((EntityConnection)context.Connection).GetMetadataWorkspace(),
125 (EntityConnection)context.Connection, context.CommandTimeout);
126 IEnumerable o = (IEnumerable)updateTranslator.GetType().InvokeMember("ProduceCommands",
127 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, updateTranslator, null);
128 Dictionary<int, object> identifierValues = new Dictionary<int, object>();
129 object generateValues = CreatePropagatorResultDictionary();
130 context.Connection.Open();
131 try
132 {
133 foreach (var item in o)
134 {
135 DbCommand cmd = (DbCommand)item.GetType().InvokeMember("CreateCommand", BindingFlags.NonPublic | BindingFlags.Instance |
136 BindingFlags.InvokeMethod, null, item,
137 new object[] { updateTranslator, identifierValues });
138 cmd.Connection = ((EntityConnection)context.Connection).StoreConnection;
139 cmd.CommandText = cmd.CommandText + " OR " + orKeyFields;
140 cmd.ExecuteReader(CommandBehavior.CloseConnection);
141 }
142 }
143 finally
144 {
145 context.Connection.Close();
146 }
147 }
148
149 public void UpdateBatch(EntityObject entity, IQueryable query)
150 {
151 if (!(query is ObjectQuery))
152 throw new Exception("only support ObjectQuery.");
153 object entityAdapter = GetEntityAdapter(_context);
154 object updateTranslator = CreateUpdateTranslator(_context.ObjectStateManager, ((EntityConnection)_context.Connection).GetMetadataWorkspace(),
155 (EntityConnection)_context.Connection, _context.CommandTimeout);
156 IEnumerable o = (IEnumerable)updateTranslator.GetType().InvokeMember("ProduceCommands",
157 BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, updateTranslator, null);
158 Dictionary<int, object> identifierValues = new Dictionary<int, object>();
159 object generateValues = CreatePropagatorResultDictionary();
160 _context.Connection.Open();
161 try
162 {
163 foreach (var item in o)
164 {
165 DbCommand cmd = (DbCommand)item.GetType().InvokeMember("CreateCommand", BindingFlags.NonPublic | BindingFlags.Instance |
166 BindingFlags.InvokeMethod, null, item,
167 new object[] { updateTranslator, identifierValues });
168 <code c
分享到:
评论

相关推荐

    Entity Framework教程资源

    Entity Framework(EF)是Microsoft开发的一个对象关系映射(ORM)框架,用于.NET应用程序。它允许开发者使用.NET语言(如C#或VB.NET)来操作数据库,而无需编写SQL语句,大大简化了数据访问层的开发工作。本教程...

    EntityFramework.Utilities:提供不存在的EntityFramework扩展,例如通过查询和批量插入进行删除和更新

    EntityFramework.Utilities提供了一些使用EF的批处理操作,而EF团队尚未为我们添加这些操作。 欢迎提出建议! 拉取请求甚至更受欢迎:) 目前,它主要针对SQL Server上的EF,但是添加提供程序应该很简单。 ###...

    EntityFramework-Extensions:实体框架批量操作通过批量保存更改,插入,更新,删除和合并SQL Server,SQL Azure,SQL Compact,MySQL和SQLite来提高实体框架的性能

    通过批量保存更改和批量操作提高实体框架的性能 通过高性能批量操作和数百种弹性功能来解决保存时的实体框架性能问题。 批量保存更改 批量插入 批量更新 批量删除 批量合并 DeleteFromQuery UpdateFromQuery ...

    spring batch in action

    DESCRIPTION Even though running batch processes is an everyday task in almost all IT departments, Java developers have had few options for writing batch applications. The result? No standards, poor ...

    EF扩展方法BulkInsert(批量添加)

    首先,EF本身并不直接支持批量插入操作,但可以通过第三方库如`EntityFramework.BulkInsert`或`Z.EntityFramework.Extensions`等来实现。这些库提供了对EF的扩展,使得我们能够批量插入数据,显著提高性能。 1. **...

    Spring Batch in Action英文pdf版

    Spring Batch in Action是一本专注于Spring Batch框架的书籍,由Arnaud Cogoluègnes、Thierry Templier、Gary Gregory和Olivier Bazoud合著,由Manning Publications公司出版。这本书详细介绍了如何使用Spring ...

    The Definitive Guide to Spring Batch, 2nd Edition.epub

    Additionally, you’ll discover how Spring Batch 4 takes advantage of Java 9, Spring Framework 5, and the new Spring Boot 2 micro-framework. After reading this book, you’ll be able to use Spring Boot ...

    Spring Batch in Action

    《Spring Batch in Action》是一本深入探讨Spring Batch框架的书籍,由Arnaud Cogoluègnes、Thierry Templier、Gary Gregory和Olivier Bazoud共同编写,Manning出版社出版。这本书旨在帮助读者理解和掌握如何使用...

    InBatch User Guide

    标题《InBatch User Guide》表明该文档是一份指南手册,其目的是为了指导用户如何使用InBatch这款软件。InBatch可能是一款与批量处理相关的专业软件,适用于需要进行批量生产或批量操作的场景,比如工业批量控制、...

    Spring batch in action

    Spring Batch是一本介绍如何使用Spring Batch框架来构建批处理应用程序的专业书籍。在软件行业中,随着各种趋势的发展,例如基于Web的应用、面向服务的架构(SOA)以及事件驱动的应用,批处理应用程序虽然存在已久,...

    Spring.Batch.in.Action.pdf

    《Spring Batch in Action》是一本深入探讨Spring Batch框架的专著,由Arnaud Cogoluègnes、Thierry Templier、Gary Gregory和Olivier Bazoud共同撰写。本书系统地介绍了Spring Batch的核心概念和技术细节,并提供...

    Spring Batch In Action

    ### Spring Batch In Action #### 知识点一:Spring Batch 的简介 - **Spring Batch** 是一个基于 Java 的强大框架,专门设计用于处理大规模数据批处理任务。 - 它为开发人员提供了一套完整的工具来构建高效、可靠...

    Manning.Spring.Batch.in.Action.Oct.2011

    《Spring Batch in Action》是Manning出版社在2011年10月出版的一本英文技术书籍,专门探讨了Spring Batch这一强大的批处理框架。Spring Batch是Spring生态系统的组成部分,旨在简化批量处理任务的开发,提供了一套...

    TERASOLUNA Batch Framework for Java Version 3.x 説明資料1

    TERASOLUNA Batch Framework for Java Version 3.x 是NTT DATA Corporation开发的一个批量处理框架,专注于简化Java环境中的批处理开发。这个框架通过组件化的方式提供了必要的功能,使得在线开发者能够快速上手进行...

    batch processing in a neural network processor

    google batch processing in a neural network processor

    dotnet core3.1 EF连接达梦数据库demo

    dotnet add package Microsoft.EntityFrameworkCore ``` 接下来,我们需要安装达梦数据库的 EF Core 驱动。这个驱动可能不在 NuGet 官方源中,需要从达梦官方网站或者其指定的第三方库源获取。安装命令如下: ```...

    Maning.Spring.Batch.in.Action.2012

    10. **Integration with Spring Framework**:Spring Batch与Spring的其他模块如Spring Data、Spring Integration等有很好的集成,可以方便地构建复杂的业务流程。 通过阅读《Spring Batch in Action》,读者将了解...

    在不加载实体的情况下从SQL语句中的LINQ查询中删除或更新多个记录-.NET开发

    Zack.EFCore.Batch中文文档中文版Entity Framework Core用户可以使用此库从SQL语句中的LINQ查询中删除或更新多个记录,而无需加载实体。 该库支持Entity Framework Core 5.0及更高版本。 说明:步骤1:安装软件包...

Global site tag (gtag.js) - Google Analytics