你的位置:首页 > ASP.net教程

[ASP.net教程]EF中的那些批量操作


在使用EF的过程中,我们经常会遇到需要批量操作数据的场景,批量操作有的时候不仅能提高性能,比如使用SqlBulkCopy进入批量插入的时候,而且比较方便操作,提高效率。那么这篇文章就来总结EF中的那些批量操作。

插入

1,单个插入

单个插入很简单,只需要构造好实体,然后调用DbSet的Add方法,最后SaveChanges就行,示例代码如下。

using (var db = new PackageFHContext()) {   // 单个插入   var entity = new ProdImage   {   ProductID = 1807,   Type = 7,   Priority = 0,   Url = " http://www.baidu.com/abc.png",   Alt = "test",   Creator = "system",   CreateOn = DateTime.Now   };   db.ProdImageSet.Add(entity);   db.SaveChanges(); }

2,批量插入

很多时候我们需要向同一数据表插入大量的数据,如果插入一条就调一次SaveChanges这样性能很低,需要频繁地访问数据库。为了解决这个问题,可以使用SqlBulkCopy来批量插入数据,这样很大地提高性能。示例代码如下。

using (var db = new PackageFHContext()) {   // 批量插入(使用到SqlBulkCopy)   var prodImages = new List<ProdImage>();   for (int i = 0; i < 50; i++)   {     prodImages.Add(new ProdImage     {     ProductID = 1807,     Type = 7,     Priority = 0,     Url = " http://www.baidu.com/abc.png",     Alt = "test" + i,     Creator = "system",     CreateOn = DateTime.Now     });   }   if (db.Database.Connection.State != ConnectionState.Open)   {     db.Database.Connection.Open();   }   PackageFH.Common.DBHelper.BulkInsert((SqlConnection)db.Database.Connection, "dbo.Pkg_ProdImage", prodImages);   if (db.Database.Connection.State != ConnectionState.Closed)   {     db.Database.Connection.Close();   } }

当然SqlBulkCopy的操作封装在了DBHelper中了,后面会附上DBHelper.BulkInsert的实现。

更新

1,单个更新

单个更新很简单,只需要先查询出那条数据,然后修改字段的值,最后SaveChanges就行。示例代码如下。

using (var db = new PackageFHContext()){  // 单个更新  var entity = db.ProdImageSet.FirstOrDefault(p => p.ImageID == 275695);  entity.Alt = "ooooooooooo";  db.SaveChanges();}

2,批量更新

我们可以先查找要更新的那些记录,然后遍历修改字段的值,最后调用SaveChanges提交更新。示例代码如下。

using (var db = new PackageFHContext()){  // 批量更新  var entitys = db.ProdImageSet.Where(p => p.ProductID == 1807 && p.Type == 7);  var j = 1;  entitys.ToList().ForEach(item =>  {    item.Alt = "update test" + j;    db.Entry(item).State = System.Data.Entity.EntityState.Modified; //不加这句也可以,为什么?    j++;  });  db.SaveChanges();}

通过SQL Profiler监控可以看到,最后生成的还是很多的UPDATE语句,也就是说每更新一条就是一个UPDATE语句。

删除

1,单个删除

示例代码如下。

using (var db = new PackageFHContext()){  // 单个删除  var entity = db.ProdImageSet.FirstOrDefault(p => p.ImageID == 275695);  db.ProdImageSet.Remove(entity);  db.SaveChanges();}

2,批量删除

示例代码如下。

using (var db = new PackageFHContext()){  // 批量删除  var entitys = db.ProdImageSet.Where(p => p.ProductID == 1783 && p.Type == 0);  entitys.ToList().ForEach(entity => db.Entry(entity).State = System.Data.Entity.EntityState.Deleted); //不加这句也可以,为什么?  db.ProdImageSet.RemoveRange(entitys);  db.SaveChanges();}

通过SQL Profiler监控,结果生成的也是多条DELETE语句。

附:DBHelper.BulkInsert的实现代码

 1 public static void BulkInsert<T>(SqlConnection conn, string tableName, IList<T> list) 2 { 3   using (var bulkCopy = new SqlBulkCopy(conn)) 4   { 5     bulkCopy.BatchSize = list.Count; 6     bulkCopy.DestinationTableName = tableName; 7  8     var table = new DataTable(); 9     var props = TypeDescriptor.GetProperties(typeof(T), new Attribute[] { new DatabaseTableColumnAttribute() })10       //Dirty hack to make sure we only have system data types 11       //i.e. filter out the relationships/collections12       .Cast<PropertyDescriptor>()13       .Where(propertyInfo => propertyInfo.PropertyType.Namespace.Equals("System"))14       .ToArray();15 16     foreach (var propertyInfo in props)17     {18       bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);19       table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType);20     }21 22     var values = new object[props.Length];23     foreach (var item in list)24     {25       for (var i = 0; i < values.Length; i++)26       {27         values[i] = props[i].GetValue(item);28       }29 30       table.Rows.Add(values);31     }32 33     bulkCopy.WriteToServer(table);34   }35 }

View Code