比较值对象的相等性时如何处理null?

时间:2010-12-01 02:09:02

标签: nhibernate null domain-driven-design equals value-objects

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

假设你实现了一个值对象(如在value object pattern by 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)
    
  3. 但是,在SQL中(至少在SQL Server的方言中),NULL = NULL为false,而NULL is NULL为真。

    我想知道在使用O / R映射器(在我的情况下,NHibernate)时预期的实现。如果实现“自然”C#相等语义,当O / R映射器将它们映射到数据库时可能会有任何不良影响吗?

    或者可能允许值对象中的可空字段无论如何都是错误的?

3 个答案:

答案 0 :(得分:1)

由于ORMs 知道关系模型,他们通常会使用SQL语义公开一种查询方式。

例如,NHibernate在HQL中提供is [not] null运算符,在Criteria中提供Restrictions.Is[Not]Null

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我认为你有两个问题:

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

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

我认为您需要单独查看这些内容,因为您的角度似乎将它们彼此过于接近,这似乎违反了一些DDD原则 - 域名不应该知道/关心持久性。

如果您不确定null的{​​{1}}值的影响,或者(a)让它返回MyField以外的其他类型; (b)让它返回string的衍生图,如string(或类似的Special Case实现); (c)或覆盖EmptyString方法,并准确说明这些实例的平等含义。

如果您的ORM无法将特定表达式(涉及Equals)转换为SQL,那么也许可以在持久层中执行更难的工作(将比较发生在SQL转换之外 - 是的,性能我知道的问题,但我肯定不是不可能解决的),有利于保持你的领域模型清洁。似乎解决方案应该来自“对领域模型最好的东西”给我。

@James Anderson提出了一个很好的观点。保留MyValueObject以获取错误和失败状态。我认为Special Case似乎越来越合适。