5

注意:我以 C# 为例,但问题在 Java 和许多其他语言中几乎相同。

假设您实现了一个值对象(如M. Fowler 的值对象模式)并且它有一些可为空的字段:

class MyValueObject
{   
    // Nullable field (with public access to keep the example short):
    public string MyField;
}

然后,当覆盖 Equals() 时,当两个值对象的 MyField 都设置为 null 时,您如何处理这种情况?他们是平等的还是不平等的?

在 C# 中,将它们视为平等似乎很明显,因为:

  1. 当您使用 C# 结构而不是类并且不覆盖 Equals() 时,这是 Equals() 的行为。

  2. 以下表达式为真:

    null == null
    object.ReferenceEquals(null, null)
    object.Equals(null, null)
    

但是,在 SQL 中(至少在 SQL Server 的方言中),NULL = NULL为假,而NULL is NULL为真。

我想知道使用 O/R 映射器(在我的例子中是 NHibernate)时需要什么实现。如果你实现“自然”的 C# 相等语义,当 O/R 映射器将它们映射到数据库时可能会有任何不良影响吗?

或者也许允许值对象中的可空字段是错误的?

4

3 回答 3

1

由于 ORM知道关系模型,因此它们通常会公开一种使用 SQL 语义进行查询的方法。

例如,NHibernateis [not] null在 HQL 和Restrictions.Is[Not]NullCriteria 中提供运算符。

当然,有一个 API 可以让这些范式发生冲突:LINQ。大多数 ORM 在与 null 进行比较(即替换为 )时会尝试做正确的事情is null,尽管有时可能会出现问题,尤其是在行为不明显的情况下。

于 2010-12-01T04:12:26.777 回答
0

我个人认为,如果它可以为空(在无错误代码中),那么它们应该被视为平等。但是,如果它不应该为空(即:客户的名称,或交货的街道地址),那么它首先不应该为空。

于 2010-12-01T02:26:32.487 回答
0

我认为你有两个问题:

一个是您需要知道一个实例MyValueObject是否等于另一个实例。

其次,这应该如何转化为持久性。

我认为您需要分别查看这些,因为您的角度似乎将它们耦合得太近,在我看来这违反了一些 DDD 原则——域不应该知道/关心持久性。

如果您不确定 (a) 的null值的影响,请让它返回除;MyField之外的其他类型。string(b) 让它返回类似的派生stringEmptyString(或类似的特殊情况实现);(c) 或重写该Equals方法并准确指定这些实例相等的含义。

如果您的 ORM 无法将特定表达式(涉及MyValueObject)转换为 SQL,那么也许可以在持久层中进行更艰苦的工作(在 SQL 转换中进行比较 - 是的,我知道性能问题,但我确定不是不可能解决)有利于保持你的领域模型干净。对我来说,似乎解决方案应该源自“什么对领域模型最好”。

@James Anderson 提出了一个很好的观点。null为错误和失败状态预留。我觉得Special Case似乎越来越合适了。

于 2010-12-01T05:53:08.310 回答