域逻辑泄漏到使用 DDD MVC.NET 应用程序中的查询中

本文关键字:NET MVC 应用程序 DDD 查询 泄漏 | 更新日期: 2023-09-27 18:33:52

我正在尝试实现一个查询,以从域模型管理的数据库获取一些数据投影到 MVC 视图

我已经读到返回静态视图的 MVC 控制器应该从查询处理程序或所谓的读取模型存储库请求 DTO,而不是使用返回完整域对象的聚合根存储库。通过这种方式,我们可以最大限度地提高性能(优化对所需数据的查询(并降低域模型滥用的风险(我们不会意外地使用 DTO 更改模型(。

问题是某些 DTO 属性无法直接映射到 DB 表字段,并且可能基于某些业务规则进行填充,或者是数据库中未隐式声明的某些条件的结果。这意味着查询作用于从域泄漏的某些逻辑。我听说这是不对的,查询应该直接过滤、排序、投影和聚合数据库表中的数据(在我的情况下使用 linq 查询和 EF(。

到目前为止,我设想了 2 种解决方案:

1( 读取模型存储库内部查询完整的域模型对象,使用它们来填充 DTO 属性(重要的是那些需要它们使用一些业务逻辑的属性(。在这里,当我们对实例化的域模型进行操作时,我们不会获得性能优势。

2(另一种解决方案是通过可能的域存储库(处理聚合根(将所有需要的数据缓存在数据库中,因此查询作用于数据字段(具有缓存值(,而无需寻址到域逻辑。然后,缓存数据的一致性将由域存储库维护,这也会导致一些开销。

例子:

1(业务规则可以像某些对象或数据的字符串表示一样简单(在整个系统中(,即格式化;

2(业务规则可以计算返回布尔值的字段,如下面的简单域模型所示:

// first aggregate root
public class AssignedForm
{
    public int Id {get;set}
    public string FormName {get;set}
    public ICollection<FormRevision> FormRevisions {get;set}
    public bool HasTrackingInformation
    {
        get
        {
           return FormRevisions.Any(
                      fr=>   fr.RevisionType==ERevisionType.DiffCopy 
                             && fr.FormRevisionItems.Any)
        }
    }
    public void CreateNextRevision()
    {
         if(HasTrackingInformation)
         {
         .......
         }
         .......
    }
}
public enum ERevisionType { FullCopy=0,DiffCopy=1 }
public class FormRevision
{
   public int Id {get;set}
   public ERevisionType RevisionType {get;set}
   public ICollection<FormRevisionItem> FormRevisionItems {get;set}
}

然后我们有一个读取模型存储库,比如IFormTrackingInfoReader返回对象集合

public class FormTrackingInfo
{
   public int AssignedFormId {get;set}
   public int AssignedFormName {get;set}
   public bool HasTrackingInformation {get;set}
}

问题是如何实现IFormTrackingInfoReader并填充HasTrackingInfo属性,坚持DRY原则,而不会泄漏到查询中。我看到人们只是返回域对象并使用映射来填充视图模型。可能这是要走的路。谢谢你的帮助。

域逻辑泄漏到使用 DDD MVC.NET 应用程序中的查询中

我不喜欢解决方案 1,域模型不是持久的无知。

就个人而言,我更喜欢解决方案2。但"永远需要的数据"可能是一个问题。如果出现新的查询需求,也许您需要一些数据迁移(我听说事件重放可以在使用事件溯源时解决问题(。所以我在想是否有一种混合解决方案:使用值对象来实现派生。我们可以使用 dto 创建新的值对象实例。

public class SomeDto {
    public String getSomeDerivation() {
         return new ValueObject(some data in this dto).someDerivation();
    }
}

在这种情况下,我认为域逻辑受到保护并与持久性分开。但我还没有在实际项目中尝试过这个。

UPDATE1:

混合解决方案不适合您的特定 FormTrackingInfo 案例,但您的解决方案二适合。一个例子是(对不起,我不是 .net 人,在 Java 中(

public class CustomerReadModel {
     private String phoneNumber;
     private String ....//other properties
     public String getPhoneNumber() {
         return phoneNumber;
     }
     public String getAreaCode() {
         return new PhoneNumber(this.phoneNumber).getAreaCode();//PhoneNumber is a value object.
     }
}

但就像我说的,我没有在实际项目中尝试过它,我认为当缓存的数据还没有准备好时,它最多是一个临时解决方案。