PM> Install-Package EntityFramework -Pre
测试用例:

class Program { static void Main(string[] args) { using (TestDBContext context = new TestDBContext()) { for (int i = 0; i < 5; i++) { var length = (int)Math.Pow(10, i); Console.WriteLine(); Console.WriteLine("Test Insert {0} datas", length); NewMethod(context, length); } } Console.WriteLine("Complete"); Console.ReadKey(); } private static void NewMethod(TestDBContext context, int length) { Console.WriteLine("------------------------------------------"); Console.WriteLine("Command\t|\tTime\t|\tDescription"); Console.WriteLine("------------------------------------------"); Stopwatch watch = Stopwatch.StartNew(); var count = context.Categories.Count(); Log(watch, "Count", "First count", count); count = context.Categories.Count(c => c.Id % 2 == 0); Log(watch, "Count", "Count name end with 1", count); context.Categories.RemoveRange(context.Categories); context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Delete", "Delete all datas", count); var list = GenerateDatas(length); Log(watch, "Gen", "Generate " + length + " Datas fro added", count); context.Categories.AddRange(list); context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Add", "Add " + length + " datas", count); foreach (var item in context.Categories.Where(c => c.Name.EndsWith("1"))) { item.Name = "Update"; } context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Update", "Update datas", count); } private static void Log(Stopwatch watch, string cmd, string desc, int count) { watch.Stop(); Console.WriteLine("{0}\t|\t{1}ms\t|\t{2},DB has {3} datas", cmd, watch.ElapsedMilliseconds, desc, count); watch.Restart(); } private static ConcurrentBag<Category> GenerateDatas(int p) { ConcurrentBag<Category> bag = new ConcurrentBag<Category>(); Parallel.For(0, p, c => { var data = new Category() { Name = "New Name" + c, Date = DateTime.Now, Description = "Test for insert" }; bag.Add(data); }); return bag; } }
结果:

1 Test Insert 1 datas 2 ------------------------------------------ 3 Command | Time | Description 4 ------------------------------------------ 5 Count | 5050ms | First count,DB has 10000 datas 6 Count | 142ms | Count name end with 1,DB has 5000 datas 7 Delete | 3869ms | Delete all datas,DB has 0 datas 8 Gen | 2ms | Generate 1 Datas fro added,DB has 0 datas 9 Add | 172ms | Add 1 datas,DB has 1 datas 10 Update | 40ms | Update datas,DB has 1 datas 11 12 Test Insert 10 datas 13 ------------------------------------------ 14 Command | Time | Description 15 ------------------------------------------ 16 Count | 2ms | First count,DB has 1 datas 17 Count | 4ms | Count name end with 1,DB has 1 datas 18 Delete | 6ms | Delete all datas,DB has 0 datas 19 Gen | 0ms | Generate 10 Datas fro added,DB has 0 datas 20 Add | 7ms | Add 10 datas,DB has 10 datas 21 Update | 18ms | Update datas,DB has 10 datas 22 23 Test Insert 100 datas 24 ------------------------------------------ 25 Command | Time | Description 26 ------------------------------------------ 27 Count | 1ms | First count,DB has 10 datas 28 Count | 5ms | Count name end with 1,DB has 5 datas 29 Delete | 32ms | Delete all datas,DB has 0 datas 30 Gen | 0ms | Generate 100 Datas fro added,DB has 0 datas 31 Add | 78ms | Add 100 datas,DB has 100 datas 32 Update | 14ms | Update datas,DB has 100 datas 33 34 Test Insert 1000 datas 35 ------------------------------------------ 36 Command | Time | Description 37 ------------------------------------------ 38 Count | 1ms | First count,DB has 100 datas 39 Count | 6ms | Count name end with 1,DB has 50 datas 40 Delete | 35ms | Delete all datas,DB has 0 datas 41 Gen | 0ms | Generate 1000 Datas fro added,DB has 0 datas 42 Add | 397ms | Add 1000 datas,DB has 1000 datas 43 Update | 42ms | Update datas,DB has 1000 datas 44 45 Test Insert 10000 datas 46 ------------------------------------------ 47 Command | Time | Description 48 ------------------------------------------ 49 Count | 3ms | First count,DB has 1000 datas 50 Count | 4ms | Count name end with 1,DB has 500 datas 51 Delete | 253ms | Delete all datas,DB has 0 datas 52 Gen | 6ms | Generate 10000 Datas fro added,DB has 0 datas 53 Add | 5203ms | Add 10000 datas,DB has 10000 datas 54 Update | 470ms | Update datas,DB has 10000 datas 55 Complete
这个结果还能接受吧.
从Profiler可以看到.
Get Count 产生一条Script

SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[Category] AS [Extent1] ) AS [GroupBy1] --或 SELECT [GroupBy1].[A1] AS [C1] FROM ( SELECT COUNT(1) AS [A1] FROM [dbo].[Category] AS [Extent1] WHERE (0 = ([Extent1].[Id] % 2)) AND ([Extent1].[Id] % 2 IS NOT NULL) ) AS [GroupBy1]
Delete产生N条Script

exec sp_executesql N'delete [dbo].[Category] where ([Id] = @0)',N'@0 int',@0=xxxxx
Insert也是产生N条Script

exec sp_executesql N'insert [dbo].[Category]([Name], [Description], [Date]) values (@0, @1, @2) select [Id] from [dbo].[Category] where @@ROWCOUNT > 0 and [Id] = scope_identity()',N'@0 nvarchar(50),@1 nvarchar(50),@2 datetime2(7)',@0=N'New Name2712',@1=N'Test for insert',@2='2013-06-07 14:10:47.3691406'
Update又是N条Script

exec sp_executesql N'update [dbo].[Category] set [Name] = @0 where ([Id] = @1) ',N'@0 nvarchar(50),@1 int',@0=N'Update',@1=149258
从执行的Script来看,能做可以把那些N条的减少为一条或少于N条.
Delete 是批量删除,可以合为一条;
Insert,即使是手工写也是写union all那种形式,这个就先不改了.
Update属于条件批量更新,可以合为一条.
批量操作,EF有个第三方的扩展库还行.
虽然EF现在出了6.0 beta版本,但这个扩展还不完全支持EF6.0
所以下个测试用EF5.0
Install-Package EntityFramework -Version 5.0.0
Install-Package EntityFramework.Extended
数据和实体类不变,把测试用例修改些.
引用命名空间
using EntityFramework.Extensions;
作例代码

static void Main(string[] args) { using (TestDBContext context = new TestDBContext()) { for (int i = 0; i < 5; i++) { var length = (int)Math.Pow(10, i); Console.WriteLine(); Console.WriteLine("Test Insert {0} datas", length); NewMethod(context, length); } } Console.WriteLine("Complete"); Console.ReadKey(); } private static void NewMethod(TestDBContext context, int length) { Console.WriteLine("------------------------------------------"); Console.WriteLine("Command\t|\tTime\t|\tDescription"); Console.WriteLine("------------------------------------------"); Stopwatch watch = Stopwatch.StartNew(); var count = context.Categories.Count(); Log(watch, "Count", "First count", count); count = context.Categories.Count(c => c.Id % 2 == 0); Log(watch, "Count", "Count name end with 1", count); context.Categories.Delete(); context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Delete", "Delete all datas", count); var list = GenerateDatas(length); Log(watch, "Gen", "Generate " + length + " Datas fro added", count); var v = ((IObjectContextAdapter)context).ObjectContext; foreach (var item in list) { v.AddObject("Categories", item); } context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Add", "Add " + length + " datas", count); context.Categories.Update(c => c.Name.EndsWith("1"), c => new Category() { Name = "Update" }); context.SaveChanges(); count = context.Categories.Count(); Log(watch, "Update", "Update datas", count); } private static void Log(Stopwatch watch, string cmd, string desc, int count) { watch.Stop(); Console.WriteLine("{0}\t|\t{1}ms\t|\t{2},DB has {3} datas", cmd, watch.ElapsedMilliseconds, desc, count); watch.Restart(); } private static ConcurrentBag<Category> GenerateDatas(int p) { ConcurrentBag<Category> bag = new ConcurrentBag<Category>(); Parallel.For(0, p, c => { var data = new Category() { Name = "New Name" + c, Date = DateTime.Now, Description = "Test for insert" }; bag.Add(data); }); return bag; }
其中用了
context.Categories.Delete(); 批量删除.
var v = ((IObjectContextAdapter)context).ObjectContext; foreach (var item in list) { v.AddObject("Categories", item); }修改Add操作方式
context.Categories.Update(c => c.Name.EndsWith("1"), c => new Category() { Name = "Update" }); 批量更新.
结果

1 Test Insert 1 datas 2 ------------------------------------------ 3 Command | Time | Description 4 ------------------------------------------ 5 Count | 1026ms | First count,DB has 10000 datas 6 Count | 6ms | Count name end with 1,DB has 5000 datas 7 Delete | 558ms | Delete all datas,DB has 0 datas 8 Gen | 2ms | Generate 1 Datas fro added,DB has 0 datas 9 Add | 342ms | Add 1 datas,DB has 1 datas 10 Update | 53ms | Update datas,DB has 1 datas 11 12 Test Insert 10 datas 13 ------------------------------------------ 14 Command | Time | Description 15 ------------------------------------------ 16 Count | 2ms | First count,DB has 1 datas 17 Count | 1ms | Count name end with 1,DB has 1 datas 18 Delete | 13ms | Delete all datas,DB has 0 datas 19 Gen | 0ms | Generate 10 Datas fro added,DB has 0 datas 20 Add | 12ms | Add 10 datas,DB has 10 datas 21 Update | 9ms | Update datas,DB has 10 datas 22 23 Test Insert 100 datas 24 ------------------------------------------ 25 Command | Time | Description 26 ------------------------------------------ 27 Count | 1ms | First count,DB has 10 datas 28 Count | 2ms | Count name end with 1,DB has 5 datas 29 Delete | 7ms | Delete all datas,DB has 0 datas 30 Gen | 0ms | Generate 100 Datas fro added,DB has 0 datas 31 Add | 53ms | Add 100 datas,DB has 100 datas 32 Update | 8ms | Update datas,DB has 100 datas 33 34 Test Insert 1000 datas 35 ------------------------------------------ 36 Command | Time | Description 37 ------------------------------------------ 38 Count | 1ms | First count,DB has 100 datas 39 Count | 1ms | Count name end with 1,DB has 50 datas 40 Delete | 6ms | Delete all datas,DB has 0 datas 41 Gen | 0ms | Generate 1000 Datas fro added,DB has 0 datas 42 Add | 418ms | Add 1000 datas,DB has 1000 datas 43 Update | 29ms | Update datas,DB has 1000 datas 44 45 Test Insert 10000 datas 46 ------------------------------------------ 47 Command | Time | Description 48 ------------------------------------------ 49 Count | 1ms | First count,DB has 1000 datas 50 Count | 1ms | Count name end with 1,DB has 500 datas 51 Delete | 21ms | Delete all datas,DB has 0 datas 52 Gen | 3ms | Generate 10000 Datas fro added,DB has 0 datas 53 Add | 4365ms | Add 10000 datas,DB has 10000 datas 54 Update | 128ms | Update datas,DB has 10000 datas 55 Complete
从Profiler可以看到.
DELETE变成一条Script了

1 DELETE [dbo].[Category] 2 FROM [dbo].[Category] AS j0 INNER JOIN ( 3 SELECT 4 [Extent1].[Id] AS [Id] 5 FROM [dbo].[Category] AS [Extent1] 6 ) AS j1 ON (j0.[Id] = j1.[Id])
UPDATE也变为一条了

1 exec sp_executesql N'UPDATE [dbo].[Category] SET 2 [Name] = @p__update__0 3 FROM [dbo].[Category] AS j0 INNER JOIN ( 4 SELECT 5 [Extent1].[Id] AS [Id] 6 FROM [dbo].[Category] AS [Extent1] 7 WHERE [Extent1].[Name] LIKE N''%1'' 8 ) AS j1 ON (j0.[Id] = j1.[Id])',N'@p__update__0 nvarchar(6)',@p__update__0=N'Update'
EF5和EF6都差不多,都能接受.