我通过存储库模式使用实体框架,并且具有显着且令人惊讶的性能问题。我已经完成了剖析,所以我非常了解会发生什么,我只是不知道该怎么办。
这是我的代码的本质(简化):
var employee = Repositories.Employees.FirstOrDefault(s => s.EmployeeId == employeeId);
employee.CompanyId = null;
Repositories.Commit();
中间线(employee.CompanyId = null
)需要花费大量时间才能完成(大约30秒)。时间不用在提交行上。
通过分析,我找到了运行这部分自动生成的EF代码的原因:
if (previousValue != null && previousValue.**Employees**.Contains(this))
{
previousValue.Employees.Remove(this);
}
这对我没有帮助,但它确实证实了问题在于EF。我真的很想知道该怎么做。我可以用其他方式(存储过程)更新列,但我真的更喜欢在任何地方使用EF。
我无法轻易编辑EF设置,因此我更倾向于不涉及此问题的建议。
更新 我通过直接对数据库运行SQL,然后从上下文刷新对象以确保EF立即检测到此更改来解决问题。
public void SetCompanyNull(Guid employeeId)
{
_ctx.ExecuteStoreCommand("UPDATE Employee SET CompanyId = NULL WHERE EmployeeId = N'" + employeeId + "'");
_ctx.Refresh(RefreshMode.StoreWins, _ctx.Employees.FirstOrDefault(s => s.EmployeeId == employeeId));
}
更新2 我也通过暂时禁用延迟加载来解决问题。
var lazyLoadDisabled = false;
if (_ctx.ContextOptions.LazyLoadingEnabled)
{
_ctx.ContextOptions.LazyLoadingEnabled = false;
lazyLoadDisabled = true;
}
this.GetEmployeeById(employeeId).CompanyId = null;
this.SaveChanges();
if (lazyLoadDisabled)
{
_ctx.ContextOptions.LazyLoadingEnabled = true;
}
我真的好奇为什么禁用延迟加载会更快(以及可能产生的副作用)
答案 0 :(得分:2)
这是EF POCO Generator模板中的问题,在某些情况下会导致意外的延迟加载。此模板为导航属性生成修正代码,因此如果您在一侧更改导航属性,则内部会转到已更改关系的另一端并尝试将关系修复为仍然一致。不幸的是,如果你的相关对象没有加载导航属性,它会触发延迟加载。
你能做什么:
Employees
Company
)
context.ContextOptions.LazyLoadingEnabled = false
答案 1 :(得分:0)
var company = Repositories.Companies.Include("Employee").FirstOrDefault(s => s.Employee.Any(q => q.EmployeeId == employeeId));
company.Employees.Remove(q => company.Employees.Where(l => l.EmployeeId == employeeId).SingleOrDefault());
Repositories.Commit();
答案 2 :(得分:0)
自动更改检测出现问题。
正如Ladislav Mrnka所指出的,当您更改涉及关系的财产时,它会尝试将更改转移给相关实体。
您可以通过在执行该操作时禁用上下文中的自动“更改跟踪”来避免这种情况。
这解释了一个类似的问题及其解决方案:
这解释了Chaneg Tracking概念: