通用存储库来更新整个聚合 [英] Generic repository to update an entire aggregate

本文介绍了通用存储库来更新整个聚合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用存储库模式来提供访问和保存我的聚合。

I am using the repository pattern to provide access to and saving of my aggregates.

问题是更新聚合,其中包括实体

例如,采取订单 OrderItem 关系。聚合根是 Order ,它管理自己的 OrderItem 集合。因此, OrderRepository 将负责更新整个聚合(将不会有$ code> OrderItemRepository )。

For example, take the Order and OrderItem relationship. The aggregate root is Order which manages its own OrderItem collection. An OrderRepository would thus be responsible for updating the whole aggregate (there would be no OrderItemRepository).

使用实体框架6处理数据持久性。

Data persistence is handled using Entity Framework 6.

更新存储库方法( DbContext.SaveChanges ()发生在别处):

Update repository method (DbContext.SaveChanges() occurs elsewhere):

public void Update(TDataEntity item)
{
    var entry = context.Entry<TDataEntity>(item);

    if (entry.State == EntityState.Detached)
    {
        var set = context.Set<TDataEntity>();

        TDataEntity attachedEntity = set.Local.SingleOrDefault(e => e.Id.Equals(item.Id));

        if (attachedEntity != null)
        {
            // If the identity is already attached, rather set the state values
            var attachedEntry = context.Entry(attachedEntity);
            attachedEntry.CurrentValues.SetValues(item);
        }
        else
        {
            entry.State = EntityState.Modified;
        }
    }
}

在上面的例子中, 订单实体将被更新,而不是其关联的 OrderItem 集合。

In my above example, only the Order entity will be updated, not its associated OrderItem collection.

我必须附加所有 OrderItem 实体吗?我如何做这个一般?

Would I have to attach all the OrderItem entities? How could I do this generically?

推荐答案

Julie Lerman给出了一个很好的方式来处理如何更新整个汇总在她的书籍编程实体框架:DbContext 中。

Julie Lerman gives a nice way to deal with how to update an entire aggregate in her book Programming Entity Framework: DbContext.

正如她写道:


当断开的实体图形到达服务器方面,
服务器将不知道实体的状态。您需要为要发现的状态提供
的方式,以便可以使上下文为
了解每个实体的状态。

When a disconnected entity graph arrives on the server side, the server will not know the state of the entities. You need to provide a way for the state to be discovered so that the context can be made aware of each entity’s state.

这种技术称为绘制状态

主要有两种方法:


  • 通过图形迭代,使用您对模型的了解,并为每个实体设置状态

  • 构建跟踪状态的通用方法

第二个选项非常好,包括创建一个界面,模型中的每个实体将实行。 Julie使用一个 IObjectWithState 接口来告诉实体的当前状态:

The second option is really nice and consists in creating an interface that every entity in your model will implement. Julie uses an IObjectWithState interface that tells the current state of the entity:

 public interface IObjectWithState
 {
  State State { get; set; }
 }
 public enum State
 {
  Added,
  Unchanged,
  Modified,
  Deleted
 }

首先要做的是自动设置为不变每个实体通过挂起在你的上下文类中添加一个构造函数的事件从数据库中检索:

First thing you have to do is to set automatically to Unchanged every entities retrieved from the DB by hooking up an event adding a constructor in your Context class:

public YourContext()
{
 ((IObjectContextAdapter)this).ObjectContext
  .ObjectMaterialized += (sender, args) =>
 {
  var entity = args.Entity as IObjectWithState;
  if (entity != null)
  {
   entity.State = State.Unchanged;
  }
 };
}

然后更改您的订单 OrderItem 类来实现 IObjectWithState 接口,并调用 ApplyChanges 接受根实体的方法作为参数:

Then change your Order and OrderItem classes to implement the IObjectWithState interface and call that ApplyChanges method accepting the root entity as parameter:

private static void ApplyChanges<TEntity>(TEntity root)
 where TEntity : class, IObjectWithState
{
 using (var context = new YourContext())
 {
  context.Set<TEntity>().Add(root);

  CheckForEntitiesWithoutStateInterface(context);

  foreach (var entry in context.ChangeTracker
  .Entries<IObjectWithState>())
  {
   IObjectWithState stateInfo = entry.Entity;
   entry.State = ConvertState(stateInfo.State);
  }
  context.SaveChanges();
 }
}

private static void CheckForEntitiesWithoutStateInterface(YourContext context)
{
 var entitiesWithoutState =
 from e in context.ChangeTracker.Entries()
 where !(e.Entity is IObjectWithState)
 select e;

 if (entitiesWithoutState.Any())
 {
  throw new NotSupportedException("All entities must implement IObjectWithState");
 }
}

最后但并非最不重要的是,不要忘记设置您的图表的正确状态在调用 ApplyChanges ;-)之前(您甚至可以将修改删除在同一个图表中说明)

Last but not least, do not forget to set the right state of your graph entites before calling ApplyChanges ;-) (you could even mix Modified and Deleted states within the same graph)

朱莉建议在他的书中更进一步:

Julie proposes to go even further in his book:


您可能会发现自己想要更精细地跟踪
修改的属性的跟踪方式。不必将整个实体
标记为已修改,您可能只希望将实际
更改的属性标记为已修改。
除了标记一个被修改的实体,客户端也是
,负责记录哪些属性被修改。执行此操作的一种方法是将修改后的属性名称列表添加到
状态跟踪界面。

you may find yourself wanting to be more granular with the way modified properties are tracked. Rather than marking the entire entity as modified, you might want only the properties that have actually changed to be marked as modified. In addition to marking an entity as modified, the client is also responsible for recording which properties have been modified. One way to do this would be to add a list of modified property names to the state tracking interface.

但是,由于我的答案已经太久了,如果你想要的话,请去阅读她的书籍了解更多; - )

But as my answer is already too long, go read her book if you want to know more ;-)

这篇关于通用存储库来更新整个聚合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆