0

我有以下实体:

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 添加到任何字典之前始终保存它(我有一堆)。我不喜欢这个选项,因为它真的不是万无一失的,而且我相信其他人以后不会注意这一点并制造可怕的错误。

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

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

4

1 回答 1

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 永远不会改变。这个解决方案已经为我服务了三年,没有任何并发​​症。但是,转换现有系统可能很复杂。

读完这篇文章后我想到了这个: 不要让 Hibernate 窃取你的身份

编辑:

有两个选项可以检测未保存的对象。一种是使用版本属性。然而,并不是所有的实体都需要这样的属性,所以我使用了一个拦截器来跟踪实体的瞬态:

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 的实现,它必须在单独的事务中访问数据库以防止跨请求锁定。

于 2013-11-02T17:02:48.743 回答