存储库是否应该在 Entity Framework 1.0 中使用相同的上下文实例
我已经开始研究我正在做的一个项目的实体框架,并通过存储库模式使用 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 个并且是事务的一部分?
如果我确实使用相同的实例,那么将其注入到存储库的构造函数中并使其在应用程序的生命周期内存活是否安全,或者是否有某种原因我看到的示例倾向于在单个方法调用中创建和处置?
感谢您提供的任何帮助。
I have started to look at the Entity Framework for a project I am doing and going down the road of using a BLL against it via the the repository pattern. As I understand it for each entity I should create a repository for it so I would have
public class UserRepository : IRepository<User>
{ ... }
and
public class AccountRepository : IRepository<Account>
{ ... }
With the examples I have seen it is common practice to create the entities context within a using statement and perform gets, updates and saves etc within.
using(var ctx = new AppEntities()
{
//do whatever
ctx.SaveChanges();
}
For simple access to the repository this would be ok, but what if I wanted to compose up an interaction between 2 (or more) repositories within by BLL...
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?
}
Would it be best to use the same AppEntities
instance for both repositories?
Also in this example a final save probably should be at the end of the block rather than having 2 like in my example and part of a transaction?
If I do use the same instance then is it safe to inject that in the constructor of the repositories and have it live for the lifetime of the app or is there some reason the examples I have seen tend to create and dispose within a single method call?
Thanks for any help provided.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在处理存储库模式时,这实际上并不是一个不寻常的问题,它归结为提供一种显式管理工作单元生命周期的方法(在实体框架的情况下是您的上下文)。
您没有指定您是进行 Web 还是 Windows 开发,但在 Web 开发的上下文中,将工作单元的生命周期设置为单个请求并不罕见。因此,当您的请求开始时,您创建上下文,然后当它结束时,您可以调用 SaveChanges(或实体框架的任何内容),这会将更改应用到您所在的所有实体在请求过程中搞乱。
在 Windows/服务上下文中,您可能希望为您的单元或工作设置某种显式生命周期管理,以便您可以根据您正在做的事情定义 UoW 的范围。我倾向于用 Conversation 比喻来包装 UoW 操作,这意味着我可以使用类似这样的东西:
当然,这掩盖了其中的一些异常管理内容,您可能希望拥有这些内容,这样您就可以失败时回滚更改。
就实施而言,这有点取决于您的基础设施。我通常使用 IoC 容器,因此我将调用
Conversation.Start()
为我创建工作单元,并设置 IoC 以返回该特定实例,因此当我创建时我的存储库他们获取当前的 UoW。您还可以在 Conversation 上创建一些工厂方法,以便您可以从对话中获取 Repository 实例。有点取决于您想要可用的 API。希望这有帮助。
This is actually not that unusual an issue when dealing with the Repository pattern, and what it boils down to is providing a way to explicitly manage the lifecycle of your unit of work (which in the case of entity framework is your context).
You didn't specify if your doing web or windows development, but in the context of web development it is not uncommon to set the lifecycle of your unit of work to a single request. So when your request starts, you create your context, and then when it is over you can call
SaveChanges
(or whatever it is for entity framework) and that would apply the changes to all of the entities you were messing with during the course of the request.In a windows/service context you'll probably want to set up some sort of explicit life cycle management for your unit or work, so you can define the scope of the UoW based on what you are doing. I tend to like the Conversation metaphor for wrapping UoW operations, which means I can use something like this:
Of course that is glossing over some exception management stuff in there, which you would want to have so you can roll-back changes in the case of a failure.
As far as implementation goes, it kinda depends on your infrastructure. I typically use an IoC container, so I'll have the call to
Conversation.Start()
create my Unit Of Work for me, and set up the IoC to return that specific instance, so when I create my Repositories they get the current UoW. You could also make some factory methods on Conversation, so that you could get your Repository instances from the conversation. Kinda depends on the API you want to have available.Hope this helps.
不,您不希望每个实体都有一个存储库。您希望将常见的功能集分组到存储库类中。所有帐户功能都应该是一个存储库。这在 ASP.NET MVC 类型的应用程序中很常见,尽管我发现这在实践中并不是最好的。
如果我要努力向存储库添加新功能,那么我稍后可能想要的是让该功能在实体本身上可用,因此我创建包含此类业务逻辑的部分类。这样我就可以执行 ShoppingCart.AddProduct(int id) 之类的操作并在分部类中执行逻辑。
另一种常见的场景是创建一次性视图模型。这实际上是我的偏好。
链接
只需记住您在 Entity 中的实体框架已经是数据源的抽象,或者可能与 LINQ To SQL 不同,后者是数据源的一对一映射。
No, you don't want each entity to have a repository. You want to group common sets of functionality into repository classes. All of the account functionality should be one repository. This is common in ASP.NET MVC type apps although I find this isn't best in practice.
If I'm going to go to the effort of adding new functionality to a repository, what I will probably want later is to have this be available on the entity itself so I create partial classes which contain this sort of business logic. That way I can do something like ShoppingCart.AddProduct(int id) and perform the logic in the partial class.
Another common scenario is creating one-off view models.This is actually my preference.
Link
Just remember that your entity in Entity Framework is already an abstraction of the data source or can be unlike LINQ To SQL where it is a one to one mapping of the data source.