0

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

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

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

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

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并按照 DRY 原则填充HasTrackingInformation属性,并且不会将域泄漏到 query中。我看到人们只是返回域对象并使用映射来填充视图模型。大概这是要走的路。谢谢您的帮助。

4

1 回答 1

0

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

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

public class SomeDto {

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

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

更新1:

混合解决方案不适合您特定的 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.
     }
}

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

于 2013-10-04T16:40:40.100 回答