添加到包集合中的NHibernate新项目在更新父实体时不会被保存

时间:2014-02-21 08:09:43

标签: nhibernate collections bag

我正在使用NHibernate 3.1.0.4000版和hbm映射文件。 当我有一个包含行李集合的实体并且我保存实体并将所有物品添加到行李中时,它会保存所有收集物品。但是,当我随后(在初始保存之后)将另一个项目添加到集合并保存实体时,它不会将新项目保存在集合中。我查看了NHibernate生成的SQL,它创建了初始的Insert SQL语句,但它没有创建Update SQL语句来更新外键值。解决方案中的所有行李都会出现此问题。

这是一个映射提取:

    <?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   default-lazy="false"
                   namespace="some_namespace"
                   assembly="some_assembly">

  <class name="Landing"
            table="[Landing]"
            select-before-update="true"
            optimistic-lock="version">
    <id name="Id"
        column="[Id]"
        unsaved-value="null">
      <generator class="assigned" />
    </id>

    <version name="Version"
            column="[Version]"
            unsaved-value="null" />

    <bag name="LandingPermits"
         cascade="all-delete-orphan"
         access="field.camelcase">
      <key column="[LandingId]" />
      <one-to-many class="LandingPermit" />
    </bag>

  </class>
</hibernate-mapping>

这是我的NHibernate存储库中的Save方法:

    public NHibernateRepository(ISessionFactory factory, string queriesAssemblyName = null, string clientName = null)
{
    this.sessionFactory = factory;
    this.queriesAssemblyName = queriesAssemblyName;
    this.clientName = clientName;

    if (!string.IsNullOrEmpty(this.queriesAssemblyName))
        LoadQueries();
}

public virtual void Save(IAggregateRoot entity)
{
    Save(new IAggregateRoot[] { entity });
}

public virtual void Save(IAggregateRoot[] entities)
{
    try
    {
        using (var session = OpenSession())
        {
            using (var transaction = session.BeginTransaction())
            {
                try
                {
                    foreach (var entity in entities)
                    {
                        if (entity.IsNew)
                            entity.AddedDateTime = DateTime.Now;
                        else
                            entity.UpdatedDateTime = DateTime.Now;

                        session.SaveOrUpdate(entity.GetType().Name, entity);
                    }
                    transaction.Commit();
                }
                catch (Exception e)
                {
                    transaction.Rollback();
                    throw e;
                }
                finally
                {
                    if (session.Connection.State == ConnectionState.Open)
                        session.Connection.Close();

                    session.Connection.Dispose();
                    session.Close();
                }
            }
        }
    }
    catch (GenericADOException e)
    {
        var sqlException = e.InnerException as SqlException;

        if ((sqlException != null) && (sqlException.Number == ForeignKeyExceptionNumber))
            throw new EntityInUseException("Save", sqlException);
        else
            throw new RepositoryException("Save", e.InnerException);
    }
    catch (StaleObjectStateException e)
    {
        throw new ConcurrencyException("Save", e, new Identity((Guid?)e.Identifier));
    }
    catch (Exception e)
    {
        throw new RepositoryException("Save", e);
    }
}

我尝试了一些方法,包括将inverse属性设置为true,但没有成功。 希望这对任何人来说都是足够的信息。 感谢

1 个答案:

答案 0 :(得分:0)

如果您的集合是inverse=false(默认值),则表示集合的所有者(父级)负责该关系。 在上面的代码中并不清楚父和子是否都是IAggregateRoot,但是如果它们都是,则意味着当你将孩子保存在不知道父母的会话中时,孩子将被保存得很好但是被添加到集合中。

如果您使用inverse=true,孩子将负责这段关系。在这种情况下,模型应该是双向的,你应该映射两端。

这里有几个选项......

  • 孩子真的是聚合根吗?也许应该和它的父母一起坚持下去?
  • 使用双向关系并使用inverse=true