我已经阅读了多个使用NHibernate标识符的地方 主键被认为是一种不好的做法,因为id是在服务器端生成的 因此我们需要服务器回复生成的ID。 (我想我也看过Ayende的帖子说ms-sql服务器可能有问题 生成标识符,这可能导致主键违规)
现在,假设我有一个非常简单的域模型:博客和帖子。每个博客都可以拥有 很多帖子和每个帖子属于完全一个博客(一对多关系) 但我们只保存帖子 - >博客关系而不是博客 - >帖子
现在假设我使用NHibernate WITH Idenitifer Id Generation,这样我就不会使用级联,所以我在我的c#代码中有这样的代码:
SaveBlogInTransaction(blog1);
SavePostsInTransaction(blog1posts);
现在,我的问题是:如果插入只能在我的代码中的一个地方完成
(没有并发问题),是否保证帖子与数据库中博客的连接有效?
我的意思是让我们看看帖子的表格架构:
PostId,PostName,PostType,BlogId
是否保证BlogId有效?
注意:每个方法都作为一个事务工作,最后它会提交db
答案 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之前保持对象检索标识。因此,插入可能发生在事务之外,并且必须手动删除记录。