实体框架/工作单元架构问题

发布于 2024-12-06 09:20:46 字数 525 浏览 0 评论 0原文

我非常熟悉 UoW、存储库模式等。但是在看到实体框架模式的各种实现时,我很好奇为什么有人会在其存储库上有 Save 或 Add 方法。如果您使用存储库来获取一个对象的新实例,我想

public Customer GetNewCustomer()
{
    Customer customer = new Customer();
     ... any initialization code here ...
    _context.Customers.AddObject(customer);
   return customer;
}

我在某些设计中已经知道有人会知道该对象,那么您可以简单地使用它

Customer customer = new Customer();

,并且它不会附加到上下文的任何地方。不过,我很喜欢私有构造函数,因此 Customer 对象有一个实例化点。考虑到这一点,在使用 UoW 模式时,在存储库上永远不要有添加/保存方法并且仅在 IUnitOfWork 接口上具有此功能不是有意义吗?

I'm very familiar with UoW, Repository Pattern, etc. but in seeing various implementations of the pattern for Entity Framework, I'm curious why anyone would have a Save or Add method on their repository. If you use the repository to get you a new instance of an object that I would imagine someone would already

public Customer GetNewCustomer()
{
    Customer customer = new Customer();
     ... any initialization code here ...
    _context.Customers.AddObject(customer);
   return customer;
}

I know in some designs, you can simply use

Customer customer = new Customer();

and its not attached anywhere to the context. However I'm a fan of private constructors so there is a single point of instantiation for a Customer object. With that in mind wouldn't it makes sense to never have an add/save method on the repository when using a UoW pattern and only have this functionality on the IUnitOfWork interface?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

栩栩如生 2024-12-13 09:20:46

当我遵循 Java 中的 Spring 习惯用法时,工作单元(和事务)与服务相关联。他们使用模型和持久性对象来满足请求。事务使用方面进行标记。

我不知道.NET 是否遵循类似的想法,但值得探索。拥有基于接口的POCO服务并让他们拥有交易。

When I follow the Spring idiom in Java, units of work (and transactions) are associated with services. They use model and persistence objects to fulfill a request. Transactions are demarked using aspects.

I don't know whether .NET follows a similar idea, but it'd be worth exploring. Have interface-based POCO services and let them own transactions.

小耗子 2024-12-13 09:20:46

我不认为你的解决方案是正确的。这会将空客户添加到当前工作单元中。这意味着如果以后的代码决定不通过当前的工作单元来拯救客户,那么它将会遇到困难。

存储库有保存实体的方法是很常见的。您正在组合域驱动设计中使用的两种模式

  • 存储库
  • 对象工厂

存储库的职责是检索或存储实体。对象工厂的职责是处理实体构建。

顺便提一句。如果存储库不是实体,则实体的私有构造函数将无法在存储库中访问(这将非常糟糕)。

I don't think that your solution is correct. That will add empty customer to current unit of work. That means that later code will have a hard time if it decide not to save customer by the current unit of work.

It is quite common that repository have method to save entity. You are combining two patterns used in Domain driven design

  • Repository
  • Object factory

Repository's responsibility is to retrieve or store entities. Object factory's responsibility is to handle entity construction.

Btw. private constructor of your entity will not be accessible in your repository if repository is not the entity (which would be quite bad).

白日梦 2024-12-13 09:20:46

...永远没有添加/保存方法不是有意义吗?
使用 UoW 模式时的存储库并且仅具有此功能
在 IUnitOfWork 接口上?

是的,我认为只在 IUnitOfWork 接口上有 Save 方法是有意义的。但是,我不再将存储库模式与 EF 一起使用。相反,我现在使用 这些 命令的变体查询模式。

如果您仔细想想,EF DbContext 实际上做了 3 件事:1.) 它充当用于读取实体状态的存储库,2.) 作为用于改变实体状态的存储库,以及 3.) 作为用于跟踪多个更改的工作单元并将它们组合成一个事务以持久保存状态突变。

那么,为什么不将这 3 个职责分成 3 个不同的接口呢?

public interface IUnitOfWork
{
    int SaveChanges();
}

public interface ICommandEntities : IQueryEntities
{
    void Create(Entity entity);
    void Update(Entity entity);
    void Purge(Entity entity);
}

public interface IQueryEntities
{
    IQueryable<AggregateRoot1> AggregateRoot1s { get; }
    IQueryable<AggregateRoot2> AggregateRoot2s { get; }
    IQUeryable<AggregateRootN> AggregateRootNs { get; }

    IQueryable<TEntity> EagerLoad<TEntity>(IQueryable<TEntity> query, 
        Expression<Func<TEntity, object>> expression)
        where TEntity : Entity;
}

然后,您可以在 DbContext 类上实现这 3 个接口。这使接口保持良好和隔离,并允许您仅依赖注入您需要的 DbContext 的那些方法。

例如,您的域应该是持久性无知的,对吧?在这种情况下,不要给任何域类依赖 IUnitOfWork 接口。相反,请在 IoC 组合根(或 MVC 操作过滤器)中处理 IUnitOfWork。然后,您的查询和命令处理程序仅处理 ICommandEntities 和 IQueryEntities 接口。

...wouldn't it makes sense to never have an add/save method on the
repository when using a UoW pattern and only have this functionality
on the IUnitOfWork interface?

Yes I think it makes sense to only have the Save method on the IUnitOfWork interface. However, I no longer use the repository pattern with EF. Instead, I now use these variations of the command & query patterns.

If you think about it, the EF DbContext is really doing 3 things: 1.) it functions as your repository for reading entity state, 2.) as your repository for mutating entity state, and 3.) as a UnitOfWork for tracking multiple changes and combining them into a single transaction to persist state mutations.

So, why not separate these 3 responsibilities into 3 different interfaces?

public interface IUnitOfWork
{
    int SaveChanges();
}

public interface ICommandEntities : IQueryEntities
{
    void Create(Entity entity);
    void Update(Entity entity);
    void Purge(Entity entity);
}

public interface IQueryEntities
{
    IQueryable<AggregateRoot1> AggregateRoot1s { get; }
    IQueryable<AggregateRoot2> AggregateRoot2s { get; }
    IQUeryable<AggregateRootN> AggregateRootNs { get; }

    IQueryable<TEntity> EagerLoad<TEntity>(IQueryable<TEntity> query, 
        Expression<Func<TEntity, object>> expression)
        where TEntity : Entity;
}

You can then implement these 3 interfaces on your DbContext class. This keeps the interfaces nice and segregated, and lets you dependency inject only those methods of the DbContext which you need.

For example, your domain should be persistence ignorant, right? In that case, don't give any of your domain classes dependencies on the IUnitOfWork interface. Instead, handle the IUnitOfWork in your IoC composition root (or in an MVC action filter). Then, your query and command handlers deal only with the ICommandEntities and IQueryEntities interfaces.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文