我可以确认这种缓慢的行为,我也找到了主要原因。我用下面的模型做了一个小测试......
public class MyClass
{
public int Id { get; set; }
public string P1 { get; set; }
// ... properties P2 to P49, all of type string
public string P50 { get; set; }
}
public class MyContext : DbContext
{
public DbSet<MyClass> MyClassSet { get; set; }
}
...还有这个测试程序...
using (var context = new MyContext())
{
var list = new List<MyClass>();
for (int i = 0; i < 1000; i++)
{
var m = new MyClass()
{
Id = i+1,
P1 = "Some text ....................................",
// ... initialize P2 to P49, all with the same text
P50 = "Some text ...................................."
}
list.Add(m);
}
Stopwatch watch = new Stopwatch();
watch.Start();
foreach (var entity in list)
{
context.Set<MyClass>().Attach(entity);
context.Entry(entity).State = System.Data.EntityState.Modified;
}
watch.Stop();
long time = watch.ElapsedMilliseconds;
}
测试 1
就是上面的代码:
--> 时间 = 29,2 秒
测试 2
注释掉这行...
//context.Entry(entity).State = System.Data.EntityState.Modified;
--> 时间 = 15,3 秒
测试 3
注释掉这行...
//context.Set<MyClass>().Attach(entity);
--> 时间 = 57.3 秒
这个结果很奇怪,因为我认为调用Attach 是不必要的,因为无论如何都会改变状态。
测试 4
去掉P6到P50的属性(所以我们实体中只有5个字符串),原代码:
--> 时间 = 3.4 秒
所以,是的,显然属性的数量非常重要。
测试 5
在循环之前添加以下行(再次使用所有 50 个属性进行建模):
context.Configuration.AutoDetectChangesEnabled = false;
--> 时间 = 1.4 秒
测试 6
再次使用 AutoDetectChangesEnabled = false,但只有 5 个属性:
--> 时间 = 1,3 秒
因此,如果不进行更改,跟踪属性的数量就不再那么重要了。
结论
到目前为止,更改跟踪机制似乎花费了大部分时间来获取附加对象属性的快照。 如果您不需要它,请禁用代码 sn- 的更改跟踪页。 (我猜在您的代码中您确实不需要更改跟踪,因为通过将实体的状态设置为 Modified 您基本上将 all 属性标记为已更改。所以 all 列在更新语句中发送到数据库。)
编辑
以上测试时间处于调试模式。但发布模式并没有太大的区别(例如:测试 1 = 28.7 秒,测试 5 = 0.9 秒)。