3

假设我想创建一个博客应用程序,其中包含这两个与 EF Code First 或 NHibernate 一起使用并从存储库层返回的简单持久性类:

public class PostPersistence
{
   public int Id { get; set; }
   public string Text { get; set; }
   public IList<LikePersistence> Likes { get; set; }
}

public class LikePersistence
{
    public int Id { get; set; }
    //... some other properties
}

我想不出一种将持久性模型映射到域模型的干净方法。我希望我的Post域模型界面看起来像这样:

public interface IPost
{
   int Id { get; }
   string Text { get; set; }
   public IEnumerable<ILike> Likes { get; }
   void Like();
}

现在下面的实现会是什么样子?也许是这样的:

public class Post : IPost
{
   private readonly PostPersistence _postPersistence;
   private readonly INotificationService _notificationService;

   public int Id 
   { 
       get { return _postPersistence.Id }
   }

   public string Text 
   { 
       get { return _postPersistence.Text; }
       set { _postPersistence.Text = value; }
   }

   public IEnumerable<ILike> Likes
   {
       //this seems really out of place
       return _postPersistence.Likes.Select(likePersistence => new Like(likePersistence ));
   }

   public Post(PostPersistence postPersistence, INotificationService notificationService)
   {
       _postPersistence = postPersistence;
       _notificationService = notificationService;
   }

   public void Like()
   {
       _postPersistence.Likes.Add(new LikePersistence());
       _notificationService.NotifyPostLiked(Id);
   }
}

我花了一些时间阅读有关 DDD 的内容,但大多数示例都是理论上的或在域层中使用了相同的 ORM 类。我的解决方案似乎真的很丑,因为实际上域模型只是 ORM 类的包装器,它似乎不是以域为中心的方法。实现方式IEnumerable<ILike> Likes也让我感到困扰,因为它不会从 LINQ to SQL 中受益。有哪些其他(具体的!)选项可以创建具有更透明持久性实现的域对象?

4

2 回答 2

2

DDD 中持久化的目标之一是持久化无知在某种程度上,这似乎是您正在努力的目标。我在您的代码示例中看到的问题之一是您的实体实现了接口并引用了存储库和服务。在 DDD 中,实体不应该实现只是自身抽象并且对存储库或服务具有实例依赖关系的接口。如果实体上的特定行为需要服务,则将该服务直接传递给相应的方法。否则,与服务和存储库的所有交互都应在实体之外完成;通常在应用程序服务中。应用程序服务在存储库和服务之间进行协调,以便调用域实体上的行为。结果,实体不' 不需要直接引用服务或存储库——它们所拥有的只是一些修改该状态并保持其完整性的状态和行为。然后,ORM 的工作就是将此状态映射到关系数据库中的表。诸如 NHibernate 之类的 ORM 允许您获得相对较大程度的执着无知

更新

我仍然不想公开带有 INotificationService 作为参数的方法,因为这个服务应该是内部的,上面的层不需要知道它。

在您当前的类实现中,与PostINotificationService具有相同或更高的可见性。如果INotificationService在基础设施层中实现,则它必须具有足够的可见性。查看六边形架构,了解现代架构中的分层概述。

作为旁注,与通知相关的功能通常可以放入域事件的处理程序中。这是实现高度解耦的强大技术。

当域对象不知道其底层 DTO 时,如果使用单独的 DTO 和域类,您将如何解决持久性同步问题?如何跟踪变化?

DTO 和相应的域类存在的原因非常不同。DTO 的目的是跨系统边界传送数据。DTO 与域对象不是一一对应的——它们可以表示域对象的一部分或对域对象的更改。跟踪更改的一种方法是让 DTO 明确其包含的更改。例如,假设您有一个允许编辑Post. 该屏幕可以捕获所做的所有更改,并将这些更改以命令 (DTO) 的形式发送到服务。该服务将加载适当的Post实体并应用命令指定的更改。

于 2012-12-05T16:06:40.783 回答
0

我认为您需要进行更多研究,查看所有选项并确定是否真的值得为完整的 DDD 实施而烦恼,过去几天我自己也去过那里,所以我会告诉你我的经验。

EF Code first 很有希望,但它也有很多问题,我在这里有一个关于这个 实体框架和领域驱动设计的条目。使用 EF,您的域模型可以由 EF 持久化,而无需创建单独的“持久性”类。您可以使用 POCO(普通旧对象)并启动并运行一个简单的应用程序,但正如我对我所说,它还没有完全成熟。

如果您使用 LINQ to SQL,那么最常见的方法是将“数据传输对象”手动映射到业务对象。对于大型应用程序而言,手动执行此操作可能会很困难,因此请检查 Automapper 之类的工具。或者,您可以简单地将 DTO 包装在一个业务对象中,例如

  public class Post
   {
      PostPersistence Post { get; set;}
      public IList<LikePersistence> Likes { get; set; }
       .....
   }

NHibernate:不确定,好久没用了。

我对此的感觉(这只是一个观点,我可能是错的)是你总是不得不做出妥协,你不会在那里找到完美的解决方案。如果你再给 EF 几年,它可能会到达那里。我认为将 DTO 映射到 DDD 对象的方法可能是最灵活的,因此寻找自动映射工具可能值得您花时间。如果你想保持简单,我最喜欢的是在需要时围绕 DTO 的一些简单包装器。

于 2012-12-05T02:04:59.920 回答