Domanda

Ho letto in più di un posto che usando l'identificatore di NHibernate come La chiave primaria è considerata una pratica errata perché gli ID vengono generati sul lato server e quindi abbiamo bisogno di una risposta dal server sugli ID generati. (Penso di aver visto anche un post di Ayende che dice che il server ms-sql potrebbe avere problemi generare identificatore e questo può causare violazioni della chiave primaria)

ora, diciamo che ho un modello di dominio molto semplice: blog e post. dove ogni blog può avere molti post e ogni post appartiene a ESATTAMENTE un blog (una o più relazioni) ma SALVIAMO SOLO IL Post - > Relazione con il blog e non con il blog - > Messaggi

ora suppongo di usare NHibernate WITH Idenitifer Id Generation in modo tale da non usare il collegamento in cascata, quindi ho nel mio codice c # qualcosa del genere:
  SaveBlogInTransaction (blog1);
  SavePostsInTransaction (blog1posts);


ora la mia domanda è questa: se l'inserimento può essere fatto solo in un posto nel mio codice (non ci sono problemi di concorrenza), è garantito che la connessione dei post al loro blog nel db sia valida?


voglio dire diamo un'occhiata allo schema della tabella dei post:
PostId, PostName, PostType, BlogId

è garantito che BlogId sarà valido?

nota: ogni metodo funziona come una transazione e alla fine fa un commit nel db

È stato utile?

Soluzione

I post avranno l'ID blog corretto anche nella tua domanda riformulata. NHibernate inserirà la riga Blog nel database non appena viene chiamato Save e recupererà il valore dell'identità generato utilizzando SCOPE_IDENTITY in quel momento. Questo valore ID verrà archiviato nell'oggetto Blog e sarà disponibile per tutti i post creati in seguito.

Questo è il motivo per cui le persone affermano che gli ID basati sull'identità non sono una buona scelta: NHibernate deve eseguire l'SQL per inserire immediatamente la riga in modo da ottenere il valore di identità corretto. Se viene utilizzato un generatore di identità diverso NHibernate può evitare di eseguire le istruzioni di inserimento SQL fino al commit della transazione poiché non è necessario contattare il database per determinare il valore dell'ID dell'oggetto.

Altri suggerimenti

Vorrei porre la domanda in modo leggermente diverso. diciamo che abbiamo questo codice:

 
     SaveBlogInTransaction (blog1);
     SaveBlogInTransaction (blog2);
     SavePostsInTransaction (post1_a, post1_b, ...); // tutti i post di blog1
     SavePostsInTransaction (post2_a, post2_b, ...); // tutti i post di blog2
  

è garantito che post1_a, post1_b, ... post 'blogid = blog1id?
è garantito che post2_a, post2_b, ... posts 'blogid = blog2id?

Penso che SCOPE_IDENTITY () non rientri qui perché inseriamo prima blog1, blog2 e solo allora blog1_posts e blog2_posts

nota: abbiamo una o più relazioni nel modello ma nel db salviamo solo per ogni post l'id del blog a cui appartiene (non abbiamo una tabella BlogPosts)

Dipende dalla tua mappatura. Se hai mappato la relazione uno-a-molti in modo tale che Blog abbia una raccolta di BlogPost e BlogPost abbia un riferimento a Blog, allora puoi creare un Blog, aggiungere Post alla sua raccolta BlogPosts e salvare solo il Blog. NHibernate si occuperà prima di inserire il record del Blog, quindi di impostare la chiave esterna sugli oggetti figlio prima di persistere. Ciò garantisce che BlogId sarà valido.

Non ho esaminato il codice sorgente di NHibernate ma sono sicuro che utilizza le migliori pratiche per recuperare l'identità dopo l'inserimento, probabilmente SCOPE_IDENTITY. Questo post sul blog discute i tre metodi.

Non sono d'accordo sul fatto che l'uso dell'identità sia una cattiva pratica. Il problema principale è che NHibernate potrebbe persistere un oggetto per recuperare un'identità prima che venga chiamato Flush. Pertanto l'inserimento può avvenire al di fuori di una transazione e il record deve essere eliminato manualmente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top