【问题标题】:NHibernate "null identifier" exception after inserting an entity插入实体后NHibernate“空标识符”异常
【发布时间】:2013-07-17 15:49:28
【问题描述】:

我无法将实体保存到 SQL Server 2005 数据库中。我将 NHibernate 2.0.0.3002 用于我的持久层。映射是典型的,带有一个整数ID,如下

<id name="Id" unsaved-value="0">
  <column name="Id"/>
  <generator class="identity" />
</id>

为简洁起见,我省略了其余部分。该应用程序正在使用具有通用保存方法的存储库类,如下所示

public void Save(T toSave)
{
    Save(new T[] { toSave });
}

public void Save(IEnumerable<T> toSave)
{
    using (ISession session = SessionFactory.OpenSession())
    {
        foreach (T item in toSave)
        {
            session.SaveOrUpdate(item);
        }
        session.Flush();
    }
}

在会话上调用 SaveOrUpdate 时,会引发异常并显示“空标识符”消息。当我检查数据库时,该行已插入所有正确的值,所以我认为问题在于 NHibernate 尝试使用@@IDENTITY 返回的值设置实体的 Id 属性。我可以通过 SQL Profiler 看到正在调用 @@IDENTITY,所以我不明白为什么会抛出异常。

有其他人遇到过这个问题吗?

【问题讨论】:

  • 您能否展示实际保存/更新的代码以及您尝试使用该 ID 的时间?
  • 我已按要求添加了代码。
  • 顺便说一句,您运行的是哪个版本的 NHibernate?

标签: nhibernate


【解决方案1】:

保存和删除都必须发生在事务中,并且事务必须在最后提交。

像这样:

public void Save(IEnumerable<T> toSave)
{
    using (ISession session = SessionFactory.OpenSession())
    {
        ITransaction transaction = Session.BeginTransaction();

        foreach (T item in toSave)
        {
            session.SaveOrUpdate(item);
        }

        transaction.Commit();           
        session.Flush();
    }
}

请注意:您需要将其包装在使用中并正确回滚...此外,您打开和提交事务的位置将根据您的情况而定。完成后您还应该关闭事务...

另外,您能否详细说明异常发生的位置?听起来你正在拯救父母,然后孩子因为父母的 id 为空而抛出?或者,它实际上是在拯救父母吗?

【讨论】:

  • 我已按照建议将其全部包装在事务中,如果引发异常则调用回滚。这解决了我的问题,谢谢。该记录确实与其他两条记录有关系,但它们早在创建该记录之前就已经存在(因此具有 ID),因此我认为这与问题无关。我很惊讶将它全部包装在事务中已修复它,但也许我需要对使用 NHibernate 会话和事务的最佳方法进行一些研究。欢迎任何指点。
  • 真的没有最好的办法,恕我直言。这完全取决于您的具体设计。通常,我有聚合根来指定子级的级联。然后,我将保存在事务中的聚合根级别包装起来。例如。答案有 cmets 所以我会做一个 answer.AddComment(comment); answerRepository.Save(答案)。我最喜欢的将保存包装在事务中的新方法来自 FNH 的(旧)源....稍后会发布。
  • ' public void Save(T entity) { WithinTransaction(() => Session.SaveOrUpdate(entity)); } private void WithinTransaction(Action action) { ITransaction transaction = Session.BeginTransaction();尝试{动作();事务.Commit(); } 捕捉(异常){ 事务。回滚();扔; } 最后 { transaction.Dispose(); } } '
  • 感谢您的建议,本。我会试试看。
【解决方案2】:

配置 log4net 可能会有所帮助,以便您可以记录和查看 NHibernate 正在执行的操作...

我曾经在使用 Access 时也遇到过 NHibernate 问题,并且能够通过设置日志记录来解决它,这样我就可以准确地查明问题的原因。

我收到的错误消息与您的不同,但this 是我描述如何解决问题的文章。也许这对你有帮助。 :)

【讨论】:

  • 我已经使用 Profiler 来检查 NHibernate 正在执行的 SQL 并且一切看起来都是正确的。它甚至调用@@IDENTITY 来检索记录的新ID,但之后抛出异常。需要说明的是,我使用的是 SQL Server,而不是 Access。
  • 我以为您曾经在 TS 中说过您正在使用 Access ?无论如何,好家伙降级所有试图帮助你但没有提供正确解决方案的人......
  • 如果我因降低您的答案而冒犯了您,我深表歉意。但是,我相信本网站的精神,不正确或误导性的答案应该被否决,以便最好的内容位于顶部。否决您的答案绝不是批评您或您链接到的博客文章。感谢您提供帮助。
  • +1 这个答案解决了我从 SQL Server 2005 测试迁移到 SQL Compact Edition 时遇到的问题。花了一个小时发疯,因为它对一个有效,但对另一个无效。阅读您的帖子,更新我的配置,使用 CE 版本保存时没有错误!
【解决方案3】:

NHibernate 开发人员非常不鼓励使用身份。我们遇到的主要问题是,在您刷新之前,您不会获得身份。在您的 Int 案例中,HiLo 将是一个很好的替代品。

话虽如此,我认为您实际上想要这样做......

<id name="Id" column="Id" unsaved-value="0">
   <generator class="identity"/>  
</id>

【讨论】:

  • 我已尝试使用此处显示的 XML,但问题仍然存在。我认为 XML 和我上面的一样,只是更简洁一些。
【解决方案4】:

我也遇到了这个错误,解决方案是像 Ben 提到的那样将它包装在一个事务中。然而,我无法让 Ben 或 gilles27 代码工作——可能是因为我对泛型和 NHibernate 不熟悉。我创建了一个稍微不同的实现(使用 Fluent NHibernate v1.3):

        public static ISession LocalDbSession = null;

    public static void Save<T>(T toSave)
    {
        using (var transaction = LocalDbSession.BeginTransaction())
        {
            LocalDbSession.Save(toSave);
            transaction.Commit();
            LocalDbSession.Flush();
        }
    }

    public static void Save<T>(IEnumerable<T> toSave)
    {
        using (var transaction = LocalDbSession.BeginTransaction())
        {
            foreach (T item in toSave)
            {
                LocalDbSession.Save(item);
            }

            transaction.Commit();
            LocalDbSession.Flush();
        }
    }

【讨论】:

    【解决方案5】:

    我认为不是生成器 class="identitiy"/>

    尝试生成器 class="guid.comp"

    【讨论】:

    • 我认为您的意思是 guid.comb,而不是 guid.comp。在任何情况下都不起作用,因为我使用的是整数键,而不是 GUID 键。
    • 虽然这在这种特殊情况下不起作用,但它确实对我有用。不错的答案
    猜你喜欢
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-11
    • 2011-09-12
    • 1970-01-01
    • 2013-12-02
    相关资源
    最近更新 更多