代码之家  ›  专栏  ›  技术社区  ›  Serhat Ozgel

如何在nhibernate中保存具有指定id的子项

  •  20
  • Serhat Ozgel  · 技术社区  · 17 年前

    我有两门课:

    public class Parent
    {
        public virtual long? ID { get; set; } // native
        public virtual IList<Child> Children { get; set; }
        public virtual string Name { get; set; }
    }
    
    public class Child
    {
        public virtual long ID { get; set; } // assigned
        public virtual string Name { get; set; }
    }
    

    child = new Child() { ID = 1, Name = "SomeName" };
    parent = new Parent() { Children = new List() { child } };
    session.Save(parent);
    

    这给了我:

    我想问题出在孩子身上指定的id。由于它有一个id,NHibernate认为它以前保存过,但事实并非如此。

    NHibernate: select child0_.ID as child1_1_, child0_.NAME as NAME1_, child0_.PARENT_ID as COMMAND7_1_, from CHILD child0_
    NHibernate: select parent0_.PARENT_ID as parent1_10_
    NHibernate: select parent0_.PARENT_ID as parent1_10_, parent0_.NAME as parent2_10_ from PARENT parent0_
    NHibernate: UPDATE CHILD SET PARENT_ID = @p0 WHERE CHILD_ID = @p1;@p0 = 2, @p1 = 1
    

    映射文件:

    <class name="MyNamespace.Child" table="CHILD">
      <id name="ID" column="CHILD_ID" type="System.Int64">
        <generator class="assigned"></generator>
      </id>
      <property name="Name" column="NAME"></property>
    </class>
    
    <class name="MyNamespace.Parent" table="PARENT">
      <id name="ID" column="PARENT_ID" type="System.Int64">
        <generator class="native"></generator>
      </id>
      <property name="Name" column="NAME"></property>
      <bag name="Children">
        <key column="PARENT_ID"></key>
        <one-to-many class="MyNamespace.Child"></one-to-many>
      </bag>
    </class>
    

    3 回复  |  直到 17 年前
        1
  •  30
  •   g .    17 年前

    当从父级级联到子级时,NHibernate使用SaveOrUpdate方法。您是对的,NHibernate需要某种方法来确定它应该执行插入还是更新。它将在三个不同的字段中查找未保存的值,以确定实体是否是新的。

    1. 身份证件
    2. 版本
    3. 时间戳

    对于分配的Id,您需要一个版本或时间戳字段来指示实体是新的。

    另一种方法是显式地对子对象调用Save()。

        2
  •  17
  •   anonymous    17 年前

    我不能100%确定这是否与您遇到的问题相同,但我的数据库是100%分配的id(ugh),我必须创建一个拦截器,跟踪子级是否持久化,以便级联工作。

    代码是剪切/粘贴的(这就是为什么它有愚蠢的名字…一开始我没有100%理解!),最初我90%的代码来自在线文档(我现在无法通过谷歌找到…对不起):

    放置在具有要级联的指定ID的对象上的基类:

    public class Persistent
    {
        private bool _saved = false;
    
        public virtual void OnSave()
        {
            _saved = true;
        }
    
        public virtual void OnLoad()
        {
            _saved = true;
        }
    
        public virtual bool IsSaved
        {
            get { return _saved; }
        }
    }
    

    添加到会话的侦听器:

    public class TrackingNumberInterceptor : EmptyInterceptor
    {
        public override bool? IsTransient(object entity)
        {
            if (entity is Persistent)
            {
                return !((Persistent)entity).IsSaved;
            }
            else
            {
                return null;
            }
        }
    
        public override bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types)
        {
            if (entity is Persistent) ((Persistent)entity).OnLoad();
            return false;
        }
    
        public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
        {
            if (entity is Persistent) ((Persistent)entity).OnSave();
            return false;
        }
    }
    

    默认情况下,对象以false的persistend(_saved)开头。当NHibernate加载或保存实体时,触发器将对象持久化(_saved)标志设置为true。

    因此,对于未持久化的新项目,它从false开始并保持false,因为NHibernate从未保存或加载它。当NHibernate检查子项是否是瞬态时,触发器会响应它是瞬态的,并且会发生一次保存,将该子项标记为持久化。现在,任何将来的使用都需要一个加载,该加载再次将其标记为持久化。

        3
  •  -1
  •   Hemanshu Bhojak    16 年前