nhibernate:实现平等的最佳做法是什么?

Mar*_*ius 7 nhibernate equality

我认为实体应该通过主键比较实现相等作为默认值,但是nhibernate文档建议使用业务标识:

最明显的方法是通过比较两个对象的标识符值来实现Equals()/ GetHashCode().如果值相同,则两者必须是相同的数据库行,因此它们是相等的(如果两者都添加到ISet,我们在ISet中只有一个元素).不幸的是,我们不能使用这种方法.NHibernate只会将标识符值分配给持久化的对象,新创建的实例将不具有任何标识符值!我们建议使用Business key equality实现Equals()和GetHashCode().

业务键平等意味着Equals()方法仅比较构成业务键的属性,这是一个在现实世界中标识我们实例的键(自然候选键)

和示例(也来自文档):

public override bool Equals(object other)
{
    if (this == other) return true;

    Cat cat = other as Cat;
    if (cat == null) return false; // null or not a cat

    if (Name != cat.Name) return false;
    if (!Birthday.Equals(cat.Birthday)) return false;

    return true;
}
Run Code Online (Sandbox Code Playgroud)

这让我头晕目眩,因为业务标识的概念(根据示例)与通过语法进行比较相同,这基本上是我与ValueObjects相关联的语义类型.不使用数据库主键作为比较值的原因是,如果未在客户端生成主键(对于ex incremental),则会更改对象的哈希码,并且您使用某种哈希表集合(例如ISet)用于存储您的实体.

我怎样才能创建一个良好的相等实现,它不会破坏相等/ hashcode的一般规则(http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx)并且也符合nhibernate规则?

ewe*_*nli 13

这是ORM的已知问题.在这里,我概述了我所知道的解决方案并给出了一些指示.

1代理/主键:自动生成

正如您所提到的,如果对象尚未保存,则不起作用.

2代理/主键:分配值

您可以决定在代码中分配PK的值,这样对象始终具有ID并可用于比较.请参阅不要让hibernate窃取您的身份.

3自然键

如果对象具有另一个自然键,而不是主键,则可以使用此键.这将是客户端实体的情况,该客户端实体具有数字主键字符串客户端编号.客户端号码标识现实世界中的客户端,是一个不会改变的自然键.

4对象值

可以使用对象值进行相等.但是你有没有提到其他缺点.如果值更改且对象位于集合中,则可能会出现问题.例如,如果你有Set两个最初不同的对象,但是当它们在集合中引用时它们会更改它们以使它们变得相等.然后你打破了合同Set.请参阅Hibernate equals和hashcode.

5混合:值+自动生成主/代理键

如果要比较的对象已经有ID,请使用它.否则,使用对象值进行比较.

都有一些优点和缺点.恕我直言,如果可以使用您的域模型,最好的是3.否则,我已经使用了5并且它有效,尽管在使用集合时仍然存在一些陷阱.我从来没用过2但是如果你找到一种在代码中生成PK的方法,这听起来也是一个明智的解决方案.也许其他人有这个指针.