【问题标题】:NHibernate Stale State IssueNHibernate 陈旧状态问题
【发布时间】:2011-11-21 23:05:26
【问题描述】:

我很好奇是否有人可以帮助我解决 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 会话并再次加载测试,它会按预期填充列表。我意识到我可能会刷新所有缓存数据,但似乎应该有一个更清洁的解决方案来解决这个问题。有什么建议吗?

【问题讨论】:

  • 你的 SessionFactory 在哪里,它应该负责创建 Sessions
  • 试试 session.Flush();在提交之前,提交应该以任何方式刷新,但显式刷新并没有害处

标签: nhibernate


【解决方案1】:

当您执行new Data.Test.TestRelate(Test) 时,不会将新的TestRelate 实例添加到所有者Test 中的集合中。 (除非你在构造函数中这样做,但我假设你只在那里设置了 TestId)。

您应该 Add() 将新的 TestRelate 实例添加到 Test.Related。当会话刷新时,Nhibernate 会注意到集合中的变化并保存新项目。

【讨论】:

    【解决方案2】:

    NHibernate 不会在提交时自动填充一对多集合。您应该简单地将TestRelate 实例添加到Related 列表中,就像没有NHibernate 一样,然后(如果您设置“级联保存”映射)甚至只提交Test 实例。

    根本不需要在程序内部使用TestID属性,因为这个属性实际上只是关系数据库映射的副产品。

    【讨论】:

    • 谢谢。你让我重新评估我为什么要那样做。一定是我刚开始使用 NHibernate 时养成的一个坏习惯。
    【解决方案3】:

    好的,所以我意识到我的方法是由于过去在利用 NHibernate 的级联方面的一些失败尝试。我将逐一介绍问题以及我为解决这些问题所做的工作。

    1. 如果我设置级联保存,当我尝试将Related 元素添加到新的Test 元素时,NHibernate 将失败,因为数据库中的TestID 值不允许为空。将属性从整数类型更改为 Test 类型本身可以解决这种情况,因为 NHibernate 能够在保存新的 Test 元素后填充字段值。
    2. 尝试通过从列表中删除 Related 记录来删除它会导致错误,因为 NHibernate 尝试在删除之前将 TestID 字段更新为 null。将inverse="true" 属性添加到Bag 映射元素可解决此问题。
    3. 删除Test 对象不会删除孤立的Related 记录。将级联属性设置为 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 问题的资源。

    【讨论】:

      猜你喜欢
      • 2019-11-08
      • 2015-08-30
      • 2020-12-30
      • 2020-12-16
      • 2015-11-29
      • 2023-01-10
      • 1970-01-01
      • 2019-01-23
      • 1970-01-01
      相关资源
      最近更新 更多