我的实体中有一个简单的值对象,称为 StartDate。它有简单的验证规则,“StartDate”不能过去。
public DateTime Value { get; }
public StartDate(DateTime value)
{
if (value < DateTime.UtcNow)
throw new StartDateCannotBePast(value);
Value = value;
}
问题是,从数据库检索实体时“StartDate”已经过去了。
我有一个简单的想法。只需使用工厂方法创建值对象而不验证它。 然后在我们的配置中我们可以做类似的事情
builder.Property(e => e.StartDate).HasConversion(
p => p.Value,
p => ScheduleItemStartDate.CreateWithoutValidation(p));
不幸的是,这将允许我们在域中创建值对象而无需验证。
所以问题是: 我应该务实一点,只使用这个工厂方法,还是有更合适的方法来实现这一点
这不是你的错;这是你的错。文学很糟糕。
问题是,从数据库检索实体时“StartDate”已经过去了。
是的。
简短的版本是,您在错误的位置建模了这个“不变量”(正如您所发现的)。
值对象的构造函数/初始化器在我们“创建”值(对象生命周期的开始)时以及当我们重构对象(对象生命周期的中间)时使用,因此谓词仅在对象生命周期的开始不需要在构造函数中强制执行。
您真正拥有的可能是与您的业务逻辑混合在一起的数据输入错误检测器(如果操作员试图在过去安排某些事情,这可能是一个打字错误!),或者您可能真的有一个从您的域驱动的策略...但该策略仅应在首次写下 StartDate 的用例期间强制执行。
这两种规则表面上看起来很相似(如果日期错误,则分支)。但在设计方面(也就是说,创建关注点正确分离的代码,以便在业务需求发生变化时很容易修改)它们是不同的,注意到这些差异很重要。
在这种情况下有帮助的一个启发是记住时间是一个输入;如果您的领域模型与系统时钟紧密耦合,那么您可能正处于最终应该解决的建模错误之中。