我很好奇是否有人可以帮我解决nHibernate中陈旧状态的问题。
首先,.Net类代码:
public class Test
{
public static Test Get(int testId) { return Factory.GetTest(testId); }
public Test() { Related = new List<TestRelate>(); }
public virtual int ID { get; protected set; }
public virtual string Name { get; set; }
public virtual IList<TestRelate> Related { get; set; }
public virtual void Delete() { Factory.Delete(this); }
public virtual void Save() { Factory.Save(this); }
}
public class TestRelate
{
protected TestRelate() { }
public TestRelate(Test test) { TestID = test.ID; }
public virtual int ID { get; protected set; }
public virtual int TestID { get; set; }
public virtual string Data { get; set; }
public virtual void Delete() { Factory.Delete(this); }
public virtual void Save() { Factory.Save(this); }
}
class Factory
{
public static Test GetTest(int testId)
{
ISession session = Session.HybridSessionBuilder.Instance;
IList<Test> ret = null;
ITransaction tx = null;
tx = session.BeginTransaction();
ret = session.CreateCriteria(typeof(Test))
.Add(Expression.Eq("ID", testId))
.List<Test>();
tx.Commit();
return ret.Count == 0 ? null : ret[0];
}
public static void Save<T>(T element)
{
ISession session = Session.HybridSessionBuilder.Instance;
ITransaction tx = null;
tx = session.BeginTransaction();
session.Save(element);
tx.Commit();
}
public static void Delete<T>(T element)
{
ISession session = Session.HybridSessionBuilder.Instance;
ITransaction tx = null;
tx = session.BeginTransaction();
session.Delete(element);
tx.Commit();
}
}
然后是nHibernate映射XML:
<class name="Data.Test.Test, Data" table="test_info">
<id name="ID" column="testid">
<generator class="native" />
</id>
<property name="Name" />
<bag name="Related" table="test_relate" lazy="false" cascade="none">
<key column="testid"></key>
<one-to-many class="Data.Test.TestRelate, Data"></one-to-many>
</bag>
</class>
<class name="Data.Test.TestRelate, Data" table="test_relate">
<id name="ID" column="relateid">
<generator class="native" />
</id>
<property name="TestID" />
<property name="Data" />
</class>
最后我遇到问题的代码:
Data.Test.Test Test = new Data.Test.Test();
Test.Name = "Hello World";
Test.Save();
Data.Test.TestRelate Relate = new Data.Test.TestRelate(Test);
Relate.Data = "How are you?";
Relate.Save();
Test = Data.Test.Test.Get(Test.ID);
int Count = Test.Related.Count;
问题是,当我运行此代码时,Test.Related
列表始终为空。但是,如果我销毁NHibernate会话并再次加载测试,它会按预期填充列表。我意识到我可能会刷新所有缓存数据,但似乎应该有一个更清洁的解决方案来解决这个问题。有什么建议吗?
答案 0 :(得分:1)
执行new Data.Test.TestRelate(Test)
时,没有任何内容可以将新的TestRelate实例添加到所有者Test中的集合中。 (除非你在构造函数中这样做,但我假设你只在那里设置了TestId。)
您应该Add()
将新的TestRelate实例添加到Test.Related。 Nhibernate会注意到集合中的更改,并在刷新会话时保存新项目。
答案 1 :(得分:1)
NHibernate在提交时不会自动填充一对多的集合。您应该只将TestRelate
个实例添加到Related
列表中,就像没有NHibernate一样,然后(如果设置“级联保存”映射)甚至只提交Test
实例。
根本不需要在程序中使用TestID
属性,因为此属性实际上只是关系数据库映射的副产品。
答案 2 :(得分:1)
好吧,所以我意识到我的方法是由于过去使用NHibernate的级联失败的尝试。我将回顾每一个问题以及我采取的措施来解决它。
Related
元素添加到新的Test
元素时,NHibernate会失败,因为数据库中的TestID
值不允许为空。将属性从整数类型更改为Test
类型本身可以解决这种情况,因为NHibernate能够在保存新的Test
元素后填充字段值。 Related
记录来删除它会导致错误,因为NHibernate在删除之前尝试将TestID
字段更新为null。将inverse="true"
属性添加到Bag
映射元素可以解决此问题。Test
对象不会删除孤立的Related
记录。将cascade属性设置为all-orphan-delete
可以解决此问题。这是所有新代码(Factory类没有变化):
public class Test
{
public static Test Get(int testId) { return Factory.GetTest(testId); }
public Test() { Related = new List<TestRelate>(); }
public virtual int ID { get; protected set; }
public virtual string Name { get; set; }
public virtual IList<TestRelate> Related { get; set; }
public virtual void Delete() { Factory.Delete(this); }
public virtual void Save() { Factory.Save(this); }
}
public class TestRelate
{
protected TestRelate() { }
public TestRelate(Test test) { Test = test; }
public virtual int ID { get; protected set; }
public virtual Test Test { get; set; }
public virtual string Data { get; set; }
public virtual void Delete() { Factory.Delete(this); }
public virtual void Save() { Factory.Save(this); }
}
映射更改:
<class name="Data.Test.Test, Data" table="test_info">
<id name="ID" column="testid">
<generator class="native" />
</id>
<property name="Name" />
<bag name="Related" table="test_relate" lazy="false" cascade="all-delete-orphan" inverse="true">
<key column="testid"></key>
<one-to-many class="Data.Test.TestRelate, Data"></one-to-many>
</bag>
</class>
<class name="Data.Test.TestRelate, Data" table="test_relate">
<id name="ID" column="relateid">
<generator class="native" />
</id>
<many-to-one name="Test" column="testid" />
<property name="Data" />
</class>
以下代码现在按预期运行:
Data.Test.Test Test;
Data.Test.TestRelate Relate;
Test = new Data.Test.Test();
Test.Name = "Hello World";
Relate = new Data.Test.TestRelate(Test);
Relate.Data = "How are you?";
Test.Related.Add(Relate);
Test.Save();
Relate = new Data.Test.TestRelate(Test);
Relate.Data = "Relate #2";
Test.Related.Add(Relate);
Test.Save();
Test.Related.RemoveAt(0);
Test.Save();
Test = Data.Test.Test.Get(Test.ID);
int Count = Test.Related.Count;
Test.Delete();
我能够从http://ayende.com收集大部分答案。我强烈推荐这个网站作为nHibernate问题的资源。