2009-10-24 5 views
1

J'ai lu à plus d'un endroit que l'utilisation de NHibernate's Identifier comme Primary Key est considérée comme une mauvaise pratique car les ID sont générés du côté serveur et par conséquent nous avons besoin d'une réponse du serveur à propos de la ID générés. (je pense que je l'ai vu aussi un message par Ayende qui dit que serveur MS-SQL peut avoir des problèmes identifiant générer et cela peut provoquer des violations de clé primaire)Utilisation de NHibernate Identifier Générateur d'identité

maintenant, disons que j'ai un très simple domaine modèle : blogs et post. où chaque blog peut avoir de nombreux postes et chaque poste appartient à EXACTEMENT un blogue (un à plusieurs) mais nous épargnons seulement post - relation> Blog et non Blog -> Messages

Supposons maintenant que je l'utilise NHibernate AVEC Idenitifer Id génération, que je ne pas utiliser en cascade donc j'ai dans mon code C# quelque chose comme ceci:

SaveBlogInTransaction(blog1);
SavePostsInTransaction(blog1posts);


maintenant, ma question est la suivante: si l'insertion peut se faire que dans un seul endroit dans mon code (il n'y a pas de problèmes de concurrence), est-il garanti que la connexion des messages à la e eir blog dans le db sera valide?


je veux dire, regardons le schéma de la table de messages:
postID, postname, PostType, blogid

est-il garanti que le blogid sera valide?

Note: chaque méthode fonctionne comme une transaction et à la fin il n'engage un à la DB

Répondre

2

Les articles auront le bon ID de blog, même dans votre question reformulée. NHibernate insère la ligne Blog dans la base de données dès que Save est appelée et récupère la valeur d'identité générée à l'aide de SCOPE_IDENTITY à ce moment-là. Cette valeur d'ID sera stockée dans l'objet Blog et sera disponible pour tous les messages créés ultérieurement. C'est pourquoi les gens disent que les ID basés sur l'identité ne sont pas un bon choix - NHibernate doit exécuter le SQL pour insérer la ligne immédiatement afin que la valeur d'identité correcte puisse être obtenue. Si un different identity generator est utilisé, NHibernate peut éviter d'exécuter les instructions d'insertion SQL jusqu'à ce que la transaction soit validée, car la base de données n'a pas besoin d'être contactée pour déterminer la valeur de l'ID de l'objet.

+0

Je suis d'accord avec Sean, l'utilisation d'une autre stratégie génératrice fera des transactions plus efficaces car NHibernate n'a pas besoin d'interroger la base de données pour obtenir l'identifiant inséré. –

-1

Cela dépend de votre cartographie. Si vous avez mappé la relation un-à-plusieurs telle que Blog a une collection de BlogPosts et BlogPost a une référence à Blog, alors vous pouvez créer un Blog, ajouter des Articles à sa collection BlogPosts, et enregistrer seulement le Blog. NHibernate prendra soin d'insérer d'abord l'enregistrement de blog puis de définir la clé étrangère sur les objets enfants avant de les persister. Cela garantit que BlogId sera valide.

Je n'ai pas regardé le code source de NHibernate mais je suis sûr qu'il utilise la meilleure pratique pour récupérer l'identité après insertion, probablement SCOPE_IDENTITY. This blog post discute les trois méthodes. Je ne suis pas d'accord avec le fait que l'utilisation de l'identité est une mauvaise pratique. Le problème principal est que NHibernate peut conserver un objet pour récupérer une identité avant que Flush ne soit appelé. Par conséquent, l'insertion peut se produire en dehors d'une transaction et l'enregistrement doit être supprimé manuellement.

+0

Je n'ai pas besoin d'une table BlogPosts parce que je n'économise que pour chaque article le blog auquel elle est connectée. J'ai une relation un-à-plusieurs dans le domaine-modèle, mais pas dans la base de données ... j'ai demandé si il est garanti que l'entrée de la poste dans la DB aura un blogid valide (et non NULL dans le cas où nous n'a pas reçu de réponse de le serveur ce qui était l'identifiant du blog précédemment inséré) –

+0

Comment le BlogId est-il généré? Je ne suis pas sûr de comprendre votre question, mais je pense que la réponse est «non». Si vous n'avez pas de relation FK dans la base de données, un BlogId valide ne peut pas être garanti. –

+0

J'ai une clé étrangère. J'utilise en fait un enregistrement actif dans le château. dans la classe Post j'ai une propriété de type Blog (mais dans la classe blog je n'ai aucune mention pour les messages ...). maintenant regarder la façon dont j'ai re-posé ma question, quand je insère d'abord plus d'un blog et seulement alors tous les messages sont insérés. est-ce correct? Je pense que SCOPE_IDENTITY ne devrait pas être utilisé ici parce que j'insère plus d'un blog. Y at-il une chance pour bug dans le blogid associé à chaque publication? –

0

Je voudrais poser la question un peu différente. disons que nous avons ce 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

est-il garanti que post1_a, post1_b, ... blogid = blog1id messages?
est-il garanti que post2_a, post2_b, ... publie 'blogid = blog2id?

je pense que SCOPE_IDENTITY() ne correspond pas ici parce que nous avons d'abord insérer blog1, blog2 et alors seulement blog1_posts et blog2_posts

Note: nous avons un à plusieurs dans le modèle, mais dans le db nous enregistrer uniquement pour chaque article l'ID du blog auquel il appartient (nous n'avons pas de table BlogPosts)

Questions connexes