Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/redis/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 工作单元模式如何适应对新聚合的引用?_C#_Design Patterns_Domain Driven Design_Unit Of Work_Atomicity - Fatal编程技术网

C# 工作单元模式如何适应对新聚合的引用?

C# 工作单元模式如何适应对新聚合的引用?,c#,design-patterns,domain-driven-design,unit-of-work,atomicity,C#,Design Patterns,Domain Driven Design,Unit Of Work,Atomicity,背景 据我所知,工作单元(UoW)模式本质上提供了事务语义。换句话说,给定由存储库持久化的聚合域,UoW类允许域的使用者将存储库方法的调用注册到原子操作中。假设我们有: interface IAggregate<TKey> { TKey Id { get; } } interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> { TEntity Get(TKe

背景

据我所知,工作单元(UoW)模式本质上提供了事务语义。换句话说,给定由存储库持久化的聚合域,UoW类允许域的使用者将存储库方法的调用注册到原子操作中。假设我们有:

interface IAggregate<TKey> {
    TKey Id { get; }
}

interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> {
    TEntity Get(TKey id);
    void Save(TEntity entity);
    void Remove(TEntity entity);
}

interface IUnitOfWork {
    void RegisterSave<TEntity>(TEntity entity);
    void RegisterRemove<TEntity>(TEntity entity);
    void RegisterUnitOfWork(IUnitOfWork uow);
    void Commit();
    void Rollback();
}
问题

考虑到上述关注点分离和对聚合边界的解释,如何为在事务上需要创建聚合并将其存储库生成的Id保存在另一个聚合中的消费者提供事务支持?例如,当
Blog.UserId
设置为
User.Id
时,如何以事务方式创建
User
Blog


我已经想出了一些答案(标记为community wiki),但我还是在这里发布我的问题,以征求反馈和更多答案。

ID类型作为参考类型是否应该更智能?这样,当存储库更新ID时,另一个聚合可以通过引用来访问它。例如:

class User : IAggregate<int> {
  int Id { get; private set; }
}

class Blog : IAggregate<int> {
  int Id { get; private set; }
  int AuthorUserId { get; set; }
}
interface IKey<TAggregate> : IEquatable<IKey<TAggregate>>
{
    /* should provide a ctor that accepts a string */

    TAggregate GetAggregateType();
    string ToString();
    bool IsAssigned { get; }
}

interface IAggregate<TSelf> where TSelf : IAggregate<TSelf>
{
    IKey<TSelf> Id { get; }
}

interface IRepository<TAggregate> where TAggregate : IAggregate<TAggregate>
{
    TAggregate Get(IKey<TAggregate> id);
    void Save(TAggregate entity);
    void Remove(TAggregate entity);
}

class User : IAggregate<User>
{
    public IKey<User> Id { get; private set; }
}

class Blog : IAggregate<Blog>
{
    public IKey<Blog> Id { get; private set; }
    public IKey<User> Author { get; private set; }
}
接口IKey:IEquatable
{
/*应该提供一个接受字符串的构造函数*/
TAggregate GetAggregateType();
字符串ToString();
布尔被分配{get;}
}
接口IAggregate,其中TSelf:IAggregate
{
IKey Id{get;}
}
接口i位置,其中TAggregate:iagregate
{
TAggregate-Get(IKey-id);
作废保存(TAggregate实体);
无效删除(TAggregate实体);
}
类用户:IAggregate
{
公共IKey Id{get;private set;}
}
班级博客:IAggregate
{
公共IKey Id{get;private set;}
公共IKey作者{get;private set;}
}

IKey
的实现与
IRepository
的实现在同一个包中提供。似乎必须放松以下模式约束之一:

  • 存储库负责生成聚合ID。相反,必须使用自然密钥
  • UoW无法注册任意
    操作
    委托。相反,允许UoW注册任意
    操作
  • 聚合间关系被对象化为ID属性。相反,请使用聚合类型属性,例如:

部分类博客:IAggregate{
用户作者{get;set;}
}
那么,我是否错误地解释了这些模式?还是在这方面它们实际上是有限的

考虑到上述关注点分离和对聚合边界的解释,如何为在事务上需要创建聚合并将其存储库生成的Id保存在另一个聚合中的消费者提供事务支持?例如,如何在Blog.UserId设置为User.Id的情况下以事务方式创建用户和博客

事情是这样的——聚合也负责绘制事务边界。这意味着——如果博客创建以某种方式失败,则不需要同时创建用户和博客,也不需要回滚用户创建

如果有这样的需求,那么您就错了


只是发布一些可能有用的快速评论

interface IAggregate<TKey> {
    TKey Id { get; }
}
interface IAggregate{
TKey Id{get;}
}
接口应该用于定义行为(角色),而不是定义实现类将包含的内容(在本例中是关于键类型的知识)

谷歌不能足够快地找到正确的解释,为什么它确实是如此,虽然。。。 我稍后再试

interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> {
  TEntity Get(TKey id);
  void Save(TEntity entity);
  void Remove(TEntity entity);
}
接口位置,其中tenty:iagregate{
TEntity-Get(TKey-id);
无效保存(潜在实体);
无效删除(潜在实体);
}
避免使用

接口IUnitOfWork{
无效登记保存(实体);
无效登记删除(实体);
无效注册表工作(IUNITOWORK uow);
无效提交();
无效回滚();
}
避免使用(这个可以解决你的问题)

接口IAggregate,其中TSelf:IAggregate
{
IKey Id{get;}
}

继续学习。很快,您将停止滥用接口和泛型。:)

恕我直言……这个问题和你自己的答案就像你在和自己交谈。为什么提出一个问题然后回答?为什么不创建一个wiki呢?很好。只是查了一下。显然,社区wiki不再可用:。正确的礼仪是什么?尽管我有答案,但我还是提出了这个问题,因为我想知道还有什么其他答案。我应该把答案写在问题里吗?我希望人们能够对他们投票,不是为了让我获得声誉,而是为了让我看到他们是如何被“人群”衡量的。将我自己的答案转移到问题中。回答自己的问题没什么错-见。只要你假装你在上,如果你不想让你的答案有代表性,你可以把你的答案标记为社区维基。请参阅对的第一个答案中的详细信息。它还解释了一个问题是如何获得社区wiki状态的。是的,我觉得聚合边界应该适应事务状态的变化。在聚合根有数百个实体时,我打破了这一点,以提高性能,不过最好实现一个延迟加载代理。无论如何,当使用UoW而不使用DDD时,我提出的一般问题仍然会出现。我不同意必须避免使用通用存储库。尽管您不会对它们进行任何多态性处理(胡说:
foreach(存储库中的var r){var e=r.Get(5);e.Id=rnd.GetNext();r.Save(e);}
),但它们确实起到了解释代码意图的支持作用,特别是当XML文档被添加到接口时。您提供的工作单元链接不能完全避免UoW。在CQR中,一个命令的执行是否会导致多个事件发生,而所有这些事件都应该以原子方式持久化?@gWiz Genericness模糊了意图。通用存储库的优势在于
interface IRepository<TEntity, in TKey> where TEntity : IAggregate<TKey> {
  TEntity Get(TKey id);
  void Save(TEntity entity);
  void Remove(TEntity entity);
}
interface IUnitOfWork {
  void RegisterSave<TEntity>(TEntity entity);
  void RegisterRemove<TEntity>(TEntity entity);
  void RegisterUnitOfWork(IUnitOfWork uow);
  void Commit();
  void Rollback();
}
interface IAggregate<TSelf> where TSelf : IAggregate<TSelf>
{
    IKey<TSelf> Id { get; }
}