使用NHibernate标识符标识生成器

时间:2009-10-24 15:26:17

标签: nhibernate nhibernate-mapping

我已经阅读了多个使用NHibernate标识符的地方 主键被认为是一种不好的做法,因为id是在服务器端生成的 因此我们需要服务器回复生成的ID。 (我想我也看过Ayende的帖子说ms-sql服务器可能有问题 生成标识符,这可能导致主键违规)

现在,假设我有一个非常简单的域模型:博客和帖子。每个博客都可以拥有 很多帖子和每个帖子属于完全一个博客(一对多关系) 但我们只保存帖子 - >博客关系而不是博客 - >帖子

现在假设我使用NHibernate WITH Idenitifer Id Generation,这样我就不会使用级联,所以我在我的c#代码中有这样的代码:

SaveBlogInTransaction(blog1);
SavePostsInTransaction(blog1posts);


现在,我的问题是:如果插入只能在我的代码中的一个地方完成 (没有并发问题),是否保证帖子与数据库中博客的连接有效?


我的意思是让我们看看帖子的表格架构:
PostId,PostName,PostType,BlogId

是否保证BlogId有效?

注意:每个方法都作为一个事务工作,最后它会提交db

3 个答案:

答案 0 :(得分:2)

即使在您重新提到的问题中,这些帖子也会拥有正确的博客ID。一旦调用了Save,NHibernate就会在数据库中插入Blog行,并在那时使用SCOPE_IDENTITY检索生成的标识值。此ID值将存储在Blog对象中,并可用于稍后创建的任何帖子。

这就是为什么人们说基于身份的ID不是一个好选择 - NHibernate必须执行SQL以立即插入行,以便可以获得正确的标识值。如果使用different identity generator,NHibernate可以避免执行SQL insert语句,直到提交事务为止,因为不需要联系数据库来确定对象ID的值。

答案 1 :(得分:0)

我想问一下这个问题有点不同。 假设我们有这个代码:


SaveBlogInTransaction(blog1);
SaveBlogInTransaction(blog2);
SavePostsInTransaction(post1_a, post1_b, ...); // all the posts of blog1
SavePostsInTransaction(post2_a, post2_b, ...); // all the posts of blog2

是否保证post1_a,post1_b,...发布'blogid = blog1id?
保证post2_a,post2_b,...发布'blogid = blog2id?

我认为SCOPE_IDENTITY()不适合这里,因为我们首先插入blog1,blog2 然后才有blog1_posts和blog2_posts

注意:我们在模型中有一对多关系,但在db中我们只为每个帖子保存 它所属的博客的ID(我们没有BlogPosts表)

答案 2 :(得分:-1)

这取决于您的映射。如果您已映射一对多关系,以便Blog拥有BlogPosts集合,而BlogPost引用了Blog,那么您可以创建一个Blog,将Posts添加到其BlogPosts集合中,并仅保存Blog。 NHibernate将首先插入Blog记录,然后在持久化之前在子对象上设置外键。这可以保证BlogId有效。

我没有看过NHibernate的源代码,但我确信它使用了插入后检索身份的最佳实践,可能是SCOPE_IDENTITY。 This blog post讨论了这三种方法。

我不同意使用身份是一种不好的做法。它的主要问题是NHibernate可能会在调用Flush之前保持对象检索标识。因此,插入可能发生在事务之外,并且必须手动删除记录。