Domain driven design DDD-使到期失效

Domain driven design DDD-使到期失效,domain-driven-design,Domain Driven Design,目前正潜入DDD,我读了埃里克·埃文斯的大部分蓝皮书。到目前为止相当有趣:) 我已经对一些聚集进行了建模,其中包含过期的实体集合。我提出了一种通用的表达方法: public class Expirable<T> { public T Value { get; protected set; } public DateTime ValidTill { get; protected set; } public Expirable(T value, DateTime

目前正潜入DDD,我读了埃里克·埃文斯的大部分蓝皮书。到目前为止相当有趣:)

我已经对一些聚集进行了建模,其中包含过期的实体集合。我提出了一种通用的表达方法:

public class Expirable<T>
{
    public T Value { get; protected set; }
    public DateTime ValidTill { get; protected set; }

    public Expirable(T value, DateTime validTill)
    {
        Value = value;
        ValidTill = validTill;
    }
}
可过期的公共类
{
公共T值{get;protected set;}
public DateTime ValidTill{get;protected set;}
公共到期日(T值、日期时间有效期)
{
价值=价值;
ValidTill=ValidTill;
}
}
我很好奇,最好的方法是使一个可过期文件无效(在集合中工作时,将其作废或省略)。到目前为止,我一直在考虑在存储库构造函数中实现这一点,因为在那里可以访问聚合并充当“集合”

我很好奇是否有人想出了解决这个问题的办法,我很高兴听到:)其他方法也很受欢迎

2013年10月1日更新:


这不是Greg Young的CQRS/ES方法的DDD。但是埃文斯的方法是,因为我刚开始写这本书和第一个应用程序。正如格雷格·杨(Greg Young)所说,如果你必须做好桌子,你必须先做几张;)

可能有多种方法来解决这个问题,但我个人会使用规范模式来解决这个问题。假设对象过期是属于域的业务规则,那么除了您编写的类之外,我还需要一个规范。以下是一个例子:

public class NotExpiredSpecification
{
    public bool IsSatisfiedBy(Expirable<T> expirableValue)
    {
        //Return true if not expired; otherwise, false.
    }
}
公共类NotExpiredSpecification
{
公共bool符合(到期价值)
{
//如果未过期,则返回true;否则返回false。
}
}
然后,当您的存储库返回聚合列表或对集合执行任何业务操作时,这可以用来将集合限制为未过期的值,这将使您的代码具有表现力,并将业务逻辑保留在域内


要了解有关规范模式的更多信息,请参阅。

我已将一个方法添加到我的抽象存储库
InvalidateExpirable
。一个例子是
UserRepository
,我在活动用户会话中删除它:
InvalidateExpirable(x=>x.sessions,(user,expiredSession)=>user.RemoveSession(expiredSession))

InvalidateExpirable
的签名如下所示:
protectedvoid InvalidateExpirable(表达式选择器、动作移除器)
。方法本身使用反射从选择器参数提取选定的属性。该属性名被粘在一个通用HQL查询中,该查询将遍历调用remove lambda的集合
user.RemoveSession
将从聚合中删除会话。通过这种方式,我让聚合负责它自己的数据。此外,在
RemoveSession
中,还会为将来的案例引发域事件

参见:示例


到目前为止效果相当好,但我必须看看它在应用程序中如何进一步发挥作用。

已经阅读了CQRS/ES(Greg Young方法)的DDD,并在MSDN网站上找到了一个关于CQRS/ES的好例子:


在本例中,他们使用命令消息队列对将来的过期消息进行排队,这将在指定时间调用聚合,从聚合中删除/停用可过期的构造。

有趣的想法,没有想到!)我已经读过有关规格的章节。这个解决方案的问题是,您必须在内存中加载完整的NotExpired集,这不是很有效。另一方面,它为我提供了一些想法供我尝试。你能详细说明一下吗?规范方法并不意味着您必须加载所有内容,事实上,您应该只加载您需要的内容。该规范只是为了让您能够过滤出正在使用的集合中的过期值。如果有一些值不需要加载到内存中,那么您的存储库将负责过滤,并且在加载存储库时会发生这种情况。这的确是正确的!我后来在编写InvalidateExpirable方法时想到了这一点(见上文)。我可以将该方法中的“查询”部分重构为规范。使域更加优雅和富有表现力。我可能以后再做,但现在已经足够了。查询并不是真正的问题,问题在于何时何地删除不变量(从性能角度看,我想这可能是个问题)。每次启动存储库或存储库中返回数据的每个方法时?(更容易出错)同样,这取决于您的上下文和存储库的结构。但是,在性能方面,您应该只从数据库中加载您需要的内容,不多也不少。确实是一个很好的模式,但是您有没有一个例子来说明在“可过期不变”场景中,
T
通常是什么?您将把强制执行不变量的代码放在何处?请参阅下面的注释以获取示例要点。您的示例仅将
UserSession
用于
T
UserSession
不是DDD意义上的不变量,它是由聚合根强制执行的业务规则。既然你提到了不变量,我只是想知道你是如何用
Expirable
实现它们的
User
就是
T
。因此,
User
是维护添加/删除/更新不变量的强制执行(
IEnumerable
)的集合。对吗。128“不变量,这是数据更改时必须维护的一致性规则…”