Nhibernate Dictionary <entity,?=“”> Entity.ID Hashcode issue </entity,>

时间:2013-11-02 14:34:33

标签: c# nhibernate dictionary

我有以下实体:

public class Entity1 
{
    public Guid ID { get; set; }

    public override int GetHashCode()
    {
        return ID.GetHashCode();
    }
}

public class Entity2
{
    public Dictionary<Entity1,int> Dict { get; set; }
}

我正在重写Entity1的GetHashCode以反映它的ID,因为它是它具有的最不可变的属性,而不是通过引用将其保留,因为我有多个会话正在运行且字典需要“会话”安全。

对于这个讨论,我在字典中有一个int值,该值并不真正相关。

使用NHibernate正确映射两个实体。

假设我有这段代码:

using (var session = GetSession())
{
    var entity1 = new Entity1();
    var entity2 = new Entity2();
    entity2.Dict[entity1] = 1;
    session.SaveOrUpdate(entity1);
    session.SaveOrUpdate(entity2);
} 

在这段代码中,Dict不会保存任何键值,因为在保存之前将entity1添加到Dict中会给它一个空ID的哈希码,就在哈希码在使用实际ID保存后更改时,会破坏字典。

我正在寻找最佳实践/最佳解决方案。

我目前的选择:

  • 记住这一点总是在将Entity1添加到任何词典之前保存它(我有一堆)。 我不喜欢这个选项,因为它真的不是万无一失的,我相信其他人以后也不会注意这一点并制造可怕的错误。

  • 保存之前 - 总是重复通过键,值集合,保存键并将它们重新输入字典,这个解决方案似乎真的缺乏性能,并导致各种不同的问题。但更重要的是 - 听起来应该有一个更好的解决方案。

处理这种情况的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

在我的项目中,我们自己做了Id代:

private int _id = -1;
public virtual Id
{
    get {return _id == -1? (_id = IdGenerator.GenerateNextId()): _id;}
    protected set {_id = value;}
}

IdGenerator是HiLo(TableHiLo或SequenceHiLo)的实现。然后使用assigned id生成策略映射所有实体:

<id name="Id" column="ID">
  <generator class="assigned" />
</id>

在这种安排中,当访问Id属性时,所有对象都将具有唯一ID,并且该ID将永远不会更改。这个解决方案已经很好地服务了我三年没有任何复杂性。但是,转换现有系统可能很复杂。

阅读完这篇文章后,我想出了这个: Don't Let Hibernate Steal Your Identity

编辑:

有两种方法可以检测未保存的对象。一个是使用版本属性。但是,并非所有实体都需要这样的属性,因此我使用拦截器来跟踪实体的瞬态状态:

public interface ITransienceAware
{
    bool IsTransient {get; set;}
}

所有实体的基类都显式地实现了这个接口(从视图中隐藏IsTransient属性,避免愚蠢的错误,因为需要将对象强制转换为ITransienceAware来改变值):

public abstract class MappedEntity: ITransienceAware // and some more unrelated interface
{
    //...................unrelated code
    bool ITransienceAware.IsTransient { get; set; }
    //...................unrelated code
}

拦截器OnLoad,OnSave方法将IsTransient更改为true。

另一个重要的实现细节是IdGenerator:它是用于Sql Server的TableHiLo和用于Oracle的SequenceHiLo的实现,它必须在分离的事务中访问数据库以防止跨请求进行锁定。