原文地址: http://msdn.microsoft.com/en-us/library/gg715124(v=vs.103) 使用 EF 4.1 或者更新版本, 你可以直接执行任何数据库命令. 在本节介绍的方法允许你对数据库执行原生的 SQL 命令. 通过 SQL 查询语句获取实体对象集 DbSet 类中的 SqlQuery 方法允许你执行一个返回实体对象集的原生 SQL 查询. 默认情况下, 返回的对象集会被上下文跟踪; 这可以通过对方法返回的 DbSqlQuery 对象调用 AsNoTracking 方法取消.返回的结果集一般为 DbSet 所对应的类型, 否则即便是其派生类也无法返回. 如果所查询的表包含了其他实体类型的数据, 那么所执行的 SQL 语句应该被正确书写, 保证只返回指定类型实体的数据. 下面的例子使用 SqlQuery 方法执行了一个 SQL 查询, 返回一个 Department 类型的实例集.
1 2 3 4 5 |
1 using (var context = new SchoolEntities()) 2 { 3 var departments = context.Departments.SqlQuery( 4 "select * from Department").ToList(); 5 } |
译注: AsNoTracking 方法必须再查询执行前调用, 查询执行后调用无效. 通过 SQL 查询获取非实体对象集 通过 Database 类中的 SqlQuery 方法来执行原生 SQL 命令, 可以返回任何类型的实例, 包括 .Net 中的原生类型. 但获取的数据将不会被上下文对象跟踪, 即使我们用这个方法来检索实体对象. 如:
1 2 3 4 |
1 using (var context = new SchoolEntities()) 2 { 3 var names = context.Database.SqlQuery<string>("select Name from Department").ToList(); 4 } |
让数据库执行原生的非查询 SQL 命令 可以通过 Database 类中的 ExecuteSqlCommand 方法执行非查询命令. 例如:
1 2 3 4 |
1 using (var context = new SchoolEntities()) 2 { 3 context.Database.ExecuteSqlCommand("update Department set Name = 'Mathematics' where Name = 'Math'"); 4 } |
ExecuteSqlCommand 方法有时会被用在 Code First 创建的数据库的初始化函数中, 用来对数据库进行一些额外的配置 (例如, 设置索引). 需要注意的是, 上下文对象并不知道执行了 ExecuteSqlCommand […]
View Details相信不少使用EF的同志们已经知道如何在EF中运行SQL命令了。我在这里简单总结下,希望对大家学习EF有所帮助! 在 EF第一个版本(.NET 3.5 SP1)中,我们只能通过将ObjectContext.Connection转换为EntityConnection,再把 EntityConnection.StoreConnection转换为SqlConnection。有了这个SqlConnection,我们再创建 SqlCommand便能顺利运行SQL命令了。(个人觉得其实很烦,呵呵) 例如: EntityConnection entityConnection = (EntityConnection)ctx.Connection; DbConnection storeConnection = entityConnection.StoreConnection; DbCommand cmd = storeConnection.CreateCommand(); cmd.CommandType = System.Data.CommandType.StoredProcedure; cmd.CommandText = "[PRO_USER_DIGITALCARD_CHECK]"; 。。。。。。。 在EF4(.NET 4)中,我们有了全新的API:ObjectContext.ExecuteStoreCommand(…)和 ObjectContext.ExecuteStoreQuery<T>(…)。从函数名不难知道前者是为了执行某一并无返回集的SQL 命令,例如UPDATE,DELETE操作;后者是执行某一个查询,并可以将返回集转换为某一对象。 using (var ctx = new MyObjectContext()) { ctx.ExecuteStoreCommand("UPDATE Person SET Name = 'Michael' WHERE PersonID = 1"); } using (var ctx = new MyObjectContext()) { var peopleViews = ctx.ExecuteStoreQuery<PersonView>("SELECT PersonID, Name FROM Person"); } public class PersonView { public int PersonID { get; set; } public string Name { get; set; } } 现在有了EF4.1,API的名字又有了些许改变。如果说DbContext将ObjectContext做了包装,那么DbContext.Database就是对应于数据库端信息的封装。执行SQL命令也自然从Database类型开始。对应于ExecuteStoreCommand和ExecuteStoreQuery<T>的是Database.ExecuteSqlCommand和Database.SqlQuery<T>。 using (var ctx = new MyDbContext()) { ctx.Database.ExecuteSqlCommand("UPDATE Person SET Name = 'Michael' WHERE PersonID = 1"); } using (var ctx = new MyDbContext()) { var peopleViews = ctx.SqlQuery<PersonView>("SELECT PersonID, Name FROM Person").ToList(); } public class PersonView { public int PersonID { get; set; } public string Name { get; set; } } from:http://www.cnblogs.com/chengxiaohui/articles/2092001.html
View Details扩展下载地址:http://efbulkinsert.codeplex.com/ 注意同时安装依赖项目,不然会报错,还有,程序中有同一个dll的其他版本,那就可能一次安装不上,得一个一个安装依赖的dll Install-Package EntityFramework.MappingAPI -Version 6.0.0.7 Install-Package EntityFramework.BulkInsert-ef6 EntityFramework.BulkInsert插入数据和EF比较 初步猜测,它应该只是把多个sql合成一个,不管怎么优化,总该最后生成的是sql。 例如:20条数据,ef调试时看到的是一次连接,20次执行sql,这个批量,估计是一次连接,20个sql组合放到一个字符串提交,这样能减少时间。 再优化也不可能把sql给减少,同一sql在数据库中执行时间也不是EF能减少的。 实测(222数据库,表FinanceReceipts): 用Stopwatch监视执行时间(单位毫秒) 一次插入200条单据测试 EF插入耗时:11,086 BulkInsert插入耗时:740 一次插入10000条单据测试 EF插入耗时:510,640 BulkInsert插入耗时:3,200 通过看代码,和猜测的实现方式差不多,不过,代码中有表映射,为什么有这些功能? 因为 Insert 比数据库自带的 SqlBulkCopy 功能慢, EntityFramework.BulkInsert扩展在优化语句传输次数的同时,也采用了速度更快的 SqlBulkCopy 去将数据插入数据库,所以在插入大数据量时,比起EF本身的插入数据,可以说快得“离谱”。 不过,利用这个SqlBulkCopy快速插入数据,也就只能在插入上有改进,对于Update,Delete数据,速度上没有什么改进的 //批量插入测试代码 [csharp] view plain copy print? StringBuilder sb = new StringBuilder(); FinanceReceipts model = ReceiptsRepository.Entities.Include(o => o.FinanceReceiptDetail).Include(o => o.FinanceBillLog).First(o => o.ReceiptId == 214539); int createCount = 10000; model.ReceiptId = 0; model.ReceiptStatus = -1; model.ReceiptNo = ""; model.FinanceBillLog.OpenSafe().ToList().ForEach(m => m.ReceiptId = 0); model.FinanceReceiptDetail.OpenSafe().ToList().ForEach(m => m.ReceiptId = 0); model.ActualCreateTime = DateTime.Now; List<FinanceReceipts> entities = new List<FinanceReceipts>(); for (int i = 0; i < createCount; i++) { FinanceReceipts temp = model.DeepCopy(); model.ReceiptNo = "ef" + i; entities.Add(temp); } Stopwatch sw = new Stopwatch(); sw.Start(); ReceiptsRepository.Insert(entities); sw.Stop(); sb.AppendFormat("EF插入耗时:{0}\r\n", sw.ElapsedMilliseconds); model.ActualCreateTime = DateTime.Now; List<FinanceReceipts> entities2 = new List<FinanceReceipts>(); for (int i = 0; i < createCount; i++) { FinanceReceipts temp = model; model.ReceiptNo = "bi" + i; entities2.Add(temp); } sw.Restart(); var ctx = (this.UnitOfWork as UnitOfWorkContextBase).DbContext; using (var transactionScope = new TransactionScope()) { // some stuff in dbcontext ctx.BulkInsert(entities2); ctx.SaveChanges(); transactionScope.Complete(); } sw.Stop(); sb.AppendFormat("BulkInsert插入耗时:{0}\r\n", sw.ElapsedMilliseconds); string ret = sb.ToString(); 插入100条,每次插入一条,循环插入测试 第1次: EF插入耗时:9006 BulkInsert插入耗时:4173 第2次: EF插入耗时:8738 BulkInsert插入耗时:3806 第3次: EF插入耗时:8784 BulkInsert插入耗时:3727 BulkInsert还是比EF本身插入数据稍微快一点,总的来说: […]
View Details这边分享一下,提升ADO.Net Entity Framework执行速度的几个方法, 技巧一 取得单一数据时,可利用【GetObjectByKey】 在预设中,ObjectContext 在查询数据的时候,并不会以快取对象作为优先查询, 会在每次查询时都向数据库要数据,对效能会产生一定的影响, 因此可以利用【GetObjectByKey】方法来对快取对象进行查询, 但如果使用【GetObejctByKey】方法进行查询,而快取对象又不存在时, 会发生 ObjectNotFoundException 例外, 要避免此问题可利用【TryGetObejctByKey】方法, 如果在快取对象中找不到数据时,会回传 false,
1 2 3 4 5 6 7 8 9 10 |
////示范一 TryGetObjectByKey using (TestEntities te = new TestEntities()) { object entity; EntityKey key = new EntityKey("TestEntities.User", "User_id", 1); te.TryGetObjectByKey(key, out entity); ////使用 entity 对象 ////.... } |
技巧二 重复执行相同查询语法,可利用已编译查询【CompiledQuery】 在我们每次下达 Linq to Entities 向数据库查询数据时, 会先编译成 Entity SQL Language ,再经由 Provider 转换成对应该数据库的语法, 如果我们在循环里,对同一个查询下达1000次的话,就要经过1000次的转换, 这是很浪费效能的, 因此 ADO.Net Entity Framework 提供了 CompiledQuery 类别, 可以进行查询的编译和快取以供重复使用, 这边简单看一个范例
1 2 3 4 5 |
/// <summary> /// 已编译查询 /// </summary> private static readonly Func<TestEntities, int ,User> CompiledQueryGetUserById = CompiledQuery.Compile<TestEntities, int, User>((te, id) => te.User.Where(a=>a.User_id == id).FirstOrDefault()); |
1 2 3 4 5 6 |
////示范二 CompiledQuery using (TestEntities te = new TestEntities()) { //// 利用 CompiledQuery 取得数据 User u = CompiledQueryGetUserById.Invoke(te, 1); } |
技巧三 只进行查询,而不异动数据时 可利用【MergeOption.NoTracking】 使用【MergeOption.NoTracking】时, 因为不会再 ObjectStateManager 中追踪对象异动状态, 因此查询时效能较好,(系统默认是使用【MergeOption.AppendOnly】) 范例
1 2 3 4 5 |
////示范三 MergeOption.NoTracking using (TestEntities te = new TestEntities()) { User u = te.User.Execute(MergeOption.NoTracking).Where(a => a.User_id == 1).FirstOrDefault(); } |
参考连结 CompiledQuery 类别 已编译的查询 (LINQ to Entities) MergeOption 列举型别 ObjectStateManager ObjectContext..::.TryGetObjectByKey 方法 from:http://it.zhaozhao.info/archives/16465
View Details【摘要】 EF(Entity Framework)是一种ORM框架,它能把我们在编程时使用对象映射到底层的数据库结构。使用EF能较大地提升数据库应用的开发效率,与ADO.NET一样,EF在使用上也很灵活。但是同其他ORM框架一样,在批量更新和插入操作时,EF有很严重的性能问题,本文主要介绍使用ADO.NET中的批量插入功能来改善EF批量插入和更新的性能问题。 【正文】 一、插入功能 用EF原生的插入功能进行批量插入,使用SQL Server Profiler对数据库进行分析会发现,每一行数据都生成了一条insert语句,这样子插入的效率是很低的。 Profiler结果 而在ADO.NET中提供为SqlServer专门提供了SqlBulkCopy类用来处理大批量的数据插入问题,因此下面介绍一下在如何将其集成在我们的项目当中。 1、在代码中使用反射从EF获取对应的数据库字段,然后使用SqlBulkCopy映射后插入 2、如果连续三次插入失败,才认为此次操作失败 二、批量更新功能 用EF原生的功能进行批量操作的代码如下,使用SQL Server Profiler对数据库进行分析会发现和插入一样会为每一行数据都会生成一条Sql更新语句。 我们想要提高批量更新操作速度的思路就是先将数据批量插入到数据库当中,然后在数据库当中进行批量更新操作。 1、和批量插入一样,为了保证程序的健壮性,只有连续三次更新都失败时,才会认为更新失败 2、在代码中拼接sql语句,使用ADO.NET生成一个与待更新数据库结构一致的临时表,然后最后再拼接出更新用的语句,最后使用ADO.NET在数据库表之间做批量更新的操作。 使用100000条数据进行测试,使用原生的方法插入时,在两分钟内没有返回结果,修改后的方法只需要700ms。修改后的批量插入也能保证在1000ms内返回结果。 from:http://www.canway.net/Original/ruanjiankaifa/0120KR016.html
View Details