注意:我以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#中,将它们视为平等似乎是显而易见的,因为:
当您使用C#结构而不是类而不重写Equals()时,这是Equals()的行为。
以下表达式为真:
null == null
object.ReferenceEquals(null, null)
object.Equals(null, null)
但是,在SQL中(至少在SQL Server的方言中),NULL = NULL
为false,而NULL is NULL
为真。
我想知道在使用O / R映射器(在我的情况下,NHibernate)时预期的实现。如果实现“自然”C#相等语义,当O / R映射器将它们映射到数据库时可能会有任何不良影响吗?
或者可能允许值对象中的可空字段无论如何都是错误的?
答案 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转换之外 - 是的,性能我知道的问题,但我肯定不是不可能解决的),有利于保持你的领域模型清洁。似乎解决方案应该来自“对领域模型最好的东西”给我。
MyValueObject
以获取错误和失败状态。我认为Special Case似乎越来越合适。