views:

347

answers:

3

i have read in more then one place that using NHibernate's Identifier as Primary Key is considered a bad practice because the id are generated at the server side and hence we need a reply from the server about the generated ids. (i think that i have also seen a post by Ayende that says that ms-sql server may have problems generating identifier and this can cause primary key violations)

now, let's say i have a very simple domain-model: blogs and post. where every blog can have many posts and each post belongs to EXACTLY one blog (one to many relationship) but WE ONLY SAVE THE Post -> Blog relationship and not the Blog -> Posts

now suppose i use NHibernate WITH Idenitifer Id Generation such that i don't use cascading so i have in my c# code something like this:

SaveBlogInTransaction(blog1);
SavePostsInTransaction(blog1posts);


now, my question is this: if the insertion can be done only in one place in my code (there are no concurrency issues), is it guaranteed that the posts' connection to their blog in the db will be valid?


i mean let's look at the Posts' table schema:
PostId, PostName, PostType, BlogId

is it guaranteed that the BlogId will be valid?

note: each method works as a transaction and at the end it does a commit to the db

A: 

It depends on your mapping. If you have mapped the one-to-many relationship such that Blog has a collection of BlogPosts and BlogPost has a reference to Blog, then you can create a Blog, add Posts to its BlogPosts collection, and save just the Blog. NHibernate will take care of inserting the Blog record first then setting the foreign key on the child objects before persisting them. This guarantees that BlogId will be valid.

I haven't looked at the NHibernate source code but I'm sure it uses the best practice for retrieving identity after insert, probably SCOPE_IDENTITY. This blog post discusses the three methods.

I don't agree that using identity is a bad practice. The main issue with it is that NHibernate may persist an object to retrieve an identity before Flush is called. Therefore the insert may happen outside of a transaction and the record has to be manually deleted.

Jamie Ide
i don't need a BlogPosts table because i only save for each postthe blog it is connected to. i have a one-to-many relationshipin the domain-model but not in the database...i asked if it is guaranteed that the post entry in the db will have a valid blogid (and not NULL in case we didn't get a response from the server what was id of the blog previously inserted)
Krembo
How is the BlogId generated? I'm not sure I understand your question but I think the answer is "no". If you don't have a FK relationship in the database then a valid BlogId can't be guaranteed.
Jamie Ide
i have a foreign key. i actually use castle-active record.in the Post class i have a property of type Blog (but in the blog class i have no mention for posts...).now look at the way i re-asked my question, when i first insert more then one blog and only then all the posts are inserted.is it ok? i think that SCOPE_IDENTITY shouldn't be used here because i insert more then one blog. is there a chance forbug in the blogid associated with each post?
Krembo
A: 

i'd like to ask the question a bit different. let's say we have this code:


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

is it guaranteed that post1_a, post1_b, ... posts' blogid = blog1id?
is it guaranteed that post2_a, post2_b, ... posts' blogid = blog2id?

i think that SCOPE_IDENTITY() doesn't fit here because we first insert blog1, blog2 and only then blog1_posts, and blog2_posts

note: we have one to many relationship in the model but in the db we only save for each post the id of of blog it belongs to (we don't have a BlogPosts table)

Krembo
+1  A: 

The posts will have the correct Blog ID even in your re-phrased question. NHibernate will insert the Blog row in the database as soon as Save is called and will retrieve the generated identity value using SCOPE_IDENTITY at that time. This ID value will be stored in the Blog object and be available for any posts created later.

This is why people say that identity-based IDs are not a good choice - NHibernate must execute the SQL to insert the row immediately so that the correct identity value can be obtained. If a different identity generator is used NHibernate can avoid executing the SQL insert statements until the transaction is committed since the database does not need to be contacted to determine the value of the object's ID.

Sean Carpenter
I agree with Sean, using another generator strategy will do more effective trasnsactions as NHibernate doesn't need to query the database to get the inserted id.
Marc Climent