C# 使我的实体框架代码更高效

C# 使我的实体框架代码更高效,c#,entity-framework,repository-pattern,C#,Entity Framework,Repository Pattern,我们有一个存储库类。虽然这个类有一些自定义行为,但它包装了一个标准的ObjectContext对象,因此它主要是标准的实体框架 目前,我们有下面的代码块,它工作正常,但性能很差。(target是一个CostingLineItem。该代码更改了此CostingLineItem的AddedByEmployee参考) 因为我们启用了延迟加载,所以这段代码同时加载target.AddedByEmployee.CostingLineItems和byEmployee.CostingLineItems集合,这

我们有一个
存储库
类。虽然这个类有一些自定义行为,但它包装了一个标准的
ObjectContext
对象,因此它主要是标准的实体框架

目前,我们有下面的代码块,它工作正常,但性能很差。(
target
是一个
CostingLineItem
。该代码更改了此
CostingLineItem
AddedByEmployee
参考)

因为我们启用了延迟加载,所以这段代码同时加载
target.AddedByEmployee.CostingLineItems
byEmployee.CostingLineItems
集合,这些集合可能有数千行

不幸的是,我无法更改此代码的延迟加载设置。我需要找到一种更有效的方法,但似乎什么都不适合我

这是我到目前为止试过的


方法1:

target.AddedByEmployeeId = byEmployee.Id;
target.AddedByEmployee = byEmployee;
Repository.Detach(target.AddedByEmployee);
target.AddedByEmployee = byEmployee;
target.AddedByEmployee.CostingLineItems.Remove(target);
target.AddedByEmployee = byEmployee;
没有效果。
AddedByEmployeeId
列仍然包含原始值。显然,最初的员工参考仍然存在,并且优先考虑


方法2:

target.AddedByEmployeeId = byEmployee.Id;
target.AddedByEmployee = byEmployee;
Repository.Detach(target.AddedByEmployee);
target.AddedByEmployee = byEmployee;
target.AddedByEmployee.CostingLineItems.Remove(target);
target.AddedByEmployee = byEmployee;
引发以下异常。同样,原始员工参考资料似乎仍然存在

违反了多重性约束。关系“Leo.Domain.FK_CostingLineItem_Employees”的角色“Employees”的多重数为1或0..1


方法3:

target.AddedByEmployeeId = byEmployee.Id;
target.AddedByEmployee = byEmployee;
Repository.Detach(target.AddedByEmployee);
target.AddedByEmployee = byEmployee;
target.AddedByEmployee.CostingLineItems.Remove(target);
target.AddedByEmployee = byEmployee;
Detach()
(依次调用
ObjectContext.Detach()
)引发以下异常:

无法分离该对象,因为它未附加到ObjectStateManager


方法4:

target.AddedByEmployeeId = byEmployee.Id;
target.AddedByEmployee = byEmployee;
Repository.Detach(target.AddedByEmployee);
target.AddedByEmployee = byEmployee;
target.AddedByEmployee.CostingLineItems.Remove(target);
target.AddedByEmployee = byEmployee;
这管用!但它仍然在加载
target.AddedByEmployee.CostingLineItems
,我希望避免这种情况


我意识到我没有在这里展示我们所有的代码(这是不可能的)。但是代码下面使用了标准的
ObjectContext
。我真正想要的是一个对实体框架有一些见解的人,他可以为我可以尝试的其他内容或我可以检查的其他内容提供一些想法


注意:我们目前正在运行Visual Studio 2012。我会看看我们是否能更新到2015年。我很想知道,自我们使用的版本以来,是否有任何变化,可以使上述某些方法在以前无法使用的情况下工作。

您是否尝试过直接从
DbSet
中删除目标,而不是从附加的
CostingLineItems
中删除目标

context.Set<CostingLineItems>().Remove(target)
context.Set().Remove(目标)

这将在不加载集合的情况下删除目标。

经过一些广泛的研究和测试,我想我确定了我的问题所在

问题是所讨论的实体刚刚在数据库中被克隆。克隆代码遵循一系列规则,这些规则规定是否同时克隆相关项或仅克隆引用


无论哪种方式,都已设置了添加的员工。因此,第二次尝试设置它,或者简单地尝试设置ID会出现问题,因为与已设置的ID冲突。

延迟加载是一个杀手,首要的好处是关闭它,但正如您所说,您不能。您可以使用上下文执行raw
SQL
吗?延迟加载是一个阻塞调用吗?如果相关集合是异步加载的,这可能无关紧要。@3dd:我认为对于我们的下一个项目,我们可能总是禁用延迟加载。不幸的是,这是一些非常复杂的代码的一部分,这些代码是由其他代码按照XML文件中定义的某些规则编写的。因此,编写原始SQL并不是解决这个问题的好方法。@RobertHarvey:它是阻塞的,而且速度明显较慢。这当然是一个有趣的建议,但此操作是由拖放操作启动的。我认为在操作完全完成之前,我们无法更新页面内容。你能发布相关的实体配置(数据注释或Fluent API)吗?谢谢,我没有尝试过,但我已经看过了。问题在于,与从集合中删除项目不同,此语法将标记该项目以进行删除。我不想实际删除该项。如果该键可为null,则应该可以将target上的员工id设置为null,然后保存以删除链接。您提到您已经尝试过,虽然它是可以为null的,但是将ID设置为null、0或其他任何东西都不会保存到数据库中。显然,仍然存在对旧项的引用,它似乎具有优先权。在调用
Remove
之后,您必须调用
SaveChanges
。@Bauss:是的,如果没有调用
SaveChanges()
,这些代码都不会起任何作用。