我已经开始查看我正在进行的项目的实体框架,并通过存储库模式对其使用BLL。据我了解每个实体,我应该为它创建一个存储库,所以我会
public class UserRepository : IRepository<User>
{ ... }
和
public class AccountRepository : IRepository<Account>
{ ... }
通过我看到的例子,通常的做法是在using语句中创建实体上下文,并在其中执行获取,更新和保存等。
using(var ctx = new AppEntities()
{
//do whatever
ctx.SaveChanges();
}
对于对存储库的简单访问,这没关系,但是如果我想在BLL中构建2个(或更多)存储库之间的交互怎么办...
public void SaveSomethingMoreComplex()
{
//BLL here stuff like validation etc
_userRepository.GetSomeData();
_accountRepository.SaveSomeData(account);
_userRepository.SaveSomeMore(user);
// Probably should have one final save that affects both repositories???
// Should be in a transaction scope also?
}
最好对两个存储库使用相同的AppEntities
实例吗?
同样在这个例子中,最终保存可能应该在块的末尾,而不是像我的例子和事务的一部分那样有2个?
如果我确实使用相同的实例,那么将它注入存储库的构造函数并使其在应用程序的生命周期中存活是安全的,或者是否有某些原因我看到的示例倾向于创建和处置单方法调用?
感谢您提供的任何帮助。
答案 0 :(得分:3)
在处理存储库模式时,这实际上并不是一个不寻常的问题,它归结为提供了一种明确管理工作单元生命周期的方法(在实体框架的情况下是您的上下文) 。
您没有指定是否进行Web或Windows开发,但在Web开发的上下文中,将您的工作单元的生命周期设置为单个请求并不罕见。因此,当您的请求开始时,您创建上下文,然后当它结束时,您可以调用SaveChanges
(或实体框架的任何内容),并将更改应用于您正在处理的所有实体请求的过程。
在Windows /服务上下文中,您可能希望为您的设备或工作设置某种明确的生命周期管理,因此您可以根据您正在执行的操作来定义UoW的范围。我倾向于喜欢 Conversation 隐喻来包装UoW操作,这意味着我可以使用这样的东西:
using(Conversation.Start())
{
// mess with the entities
} // Dispose on the object returned from Start will
// Save Changes and close the session
当然,这会掩盖一些异常管理内容,您可能希望这样做,以便在发生故障时回滚更改。
就实施而言,它有点取决于您的基础设施。我通常使用IoC容器,因此我将调用Conversation.Start()
为我创建我的工作单元,并设置IoC以返回该特定实例,因此当我创建我的存储库时,他们获得当前的UoW 。您还可以在Conversation上创建一些工厂方法,以便从对话中获取Repository实例。 Kinda取决于您想要的API。
希望这有帮助。
答案 1 :(得分:0)
不,您不希望每个实体都有一个存储库。您希望将常用功能集分组到存储库类中。所有帐户功能都应该是一个存储库。这在ASP.NET MVC类型的应用程序中很常见,但我发现这在实践中并不是最好的。
如果我要努力向存储库添加新功能,我稍后可能想要的是让它在实体本身上可用,因此我创建了包含这种业务逻辑的部分类。这样我可以做一些像ShoppingCart.AddProduct(int id)这样的东西,并在分部类中执行逻辑。
另一种常见情况是创建一次性视图模型。这实际上是我的偏好。
http://blogs.msdn.com/b/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx
请记住,实体框架中的实体已经是数据源的抽象,或者可能与LINQ To SQL不同,它是数据源的一对一映射。