我正在与另一位开发人员讨论是否在我们的Entity Framework 5存储库中公开了repo.SaveChanges()
方法。
我们正在考虑拥有一个自动保存此类更改的回购(快速而肮脏的示例):
public class Repo {
private OurEfContext _context = new OurEfContext();
public void PersistCustomer(Customer cust)
{
// update customer code here
_context.SaveChanges(); // <-- is this okay?
}
}
我们正在考虑的另一个选择是公开一个单独的Repo.PersistChanges()方法,如下所示:
public class Repo {
private OurEfContext _context = new OurEfContext();
public void PersistCustomer(Customer cust)
{
// update customer code here
// no call to _context.SaveChanges();
}
public void PersistChanges()
{
_context.SaveChanges();
}
}
我见过的大多数例子都使用第二种模式。一种模式比另一种更“正确”吗?
答案 0 :(得分:8)
每次更改后保存都会阻止您保存批量实体。在某些图形结构中,这可能是正确性问题,在其他情况下,它只会驱动CPU负载。 SaveChanges
的成本不仅仅是写作,还包括遍历加载到上下文中的实体。
为什么反对实体框架?做,它想要你做什么:保存批次并在完成对实体的所有更改后最后调用SaveChanges
。
方法PersistCustomer
被错误地命名:它坚持一切,而不仅仅是客户。您无法使用EF保留单个实体。您的抽象(存储库)已损坏。
人们经常将EF包装在通用存储库中,该存储库不添加任何功能但会删除功能。这从来没有对我有意义。
答案 1 :(得分:1)
出于以下两个原因,我移至第一种方法:
1)有时(不经常)我忘记调用SaveChanges()
方法。例如,当我不得不同时提交一个事务(或者我保存了更改但忘记提交一个事务)并且我的测试不理想时没有捕获到这种错误(类似于您不叫{{1 }}每次您在业务实体中进行更改时都会起作用,因为您可以忘记调用它(即使这不是唯一原因)。
2)可以将存储库接口转换为内存存储库(出于测试目的),并且没有意义调用Validate()
,这可能会造成混淆,因为标准集合没有这种方法和实现应该对用户隐藏。
如果需要添加集合,可以向存储库SaveChanges()
添加另一个方法,执行Import(List<Customer> customers)
,然后调用foreach
。对于用户来说也很清楚,存在一些优化的方法。
如果我需要在多个存储库上执行多个操作,则可以通过事务包装所有操作(可以在关系数据库中锁定所有微小的更改,以避免不一致或死锁,直到未整体提交事务为止)。
但是我认为第一种或第二种方法没有更好的选择,两者都需要权衡取舍,这可能是个人喜好问题?
答案 2 :(得分:0)
我倾向于支持第二种方法。
第一个可能会“隐藏”保存操作,并且对用户来说会更好看, 但不要忘记你正在失去对储蓄行动的控制权。 如果您发现自己更新了多个实体,这将导致多个分离的更改的开销,而不是让它们立即执行 - 这意味着更多的执行时间。
虽然可能感觉冗余地调用“SaveChanges”,但第二种方法可以让您一次保存多个更改 =无开销。
我发现通过消除改善作为不必要行为的表现的能力来限制自己。