我有以下实体:
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添加到任何词典之前保存它(我有一堆)。 我不喜欢这个选项,因为它真的不是万无一失的,我相信其他人以后也不会注意这一点并制造可怕的错误。
保存之前 - 总是重复通过键,值集合,保存键并将它们重新输入字典,这个解决方案似乎真的缺乏性能,并导致各种不同的问题。但更重要的是 - 听起来应该有一个更好的解决方案。
处理这种情况的最佳方法是什么?
答案 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的实现,它必须在分离的事务中访问数据库以防止跨请求进行锁定。