2010-09-15 14 views
1

J'ai deux entités, une Shelf et Product:Pourquoi Session.Flush() est-il requis pour la persistance des relations?

public class Shelf 
{ 
    public virtual IList<Product> Products { get; set; } 

    public Shelf() 
    { 
     Products = new List<Product>(); 
    } 
} 

public class Product 
{ 
    public virtual string Name { get; set; } 
} 

Fondamentalement, un PUT Shelf peut contenir beaucoup Products, et un Product peut être mis sur un grand nombre Shelves. Ainsi, il existe une relation plusieurs-à-plusieurs unidirectionnelle entre Shelf et Product. Quand je lance le code suivant:

var shelf = new Shelf(); 
var product = new Product { Name = "Peas" }; 
shelf.Products.Add(product); 

using (var session = SessionFactory.OpenSession()) 
{ 
    session.Save(shelf); 
} 

NHibernate sauvera le Product et le Shelf, mais il ne sauvera pas la relation entre eux, donc si vous récupérez le Shelf, il contiendra zéro Products. Cependant, si j'ajoute un appel session.Flush(), il enregistrera correctement la relation de sorte que la récupération du Shelf retournera Product.

Ce blog détails post ma question:

http://www.neeraj.name/2005/07/02/hibernate-session-close-does-not-call-session-flush.html

Cependant, je me demandais pourquoi je besoin de cet appel session.Flush(). Il semble contre-intuitif que sauver un Shelf avec le bon comportement en cascade permettra d'économiser le Product, mais ne parvient pas à établir la relation entre les deux à moins que je vide la session. Il me semble qu'un appel Save() devrait sauver tout, et pas seulement l'entité eux-mêmes sans leurs relations.

Répondre

1

Save marque seulement une entité à persista et génère un identifiant. Il ne conserve pas les modifications apportées à la base de données.

Tous les changements (insertions, mises à jour et suppressions) sont effectués lorsque flushing, ce qui peut se produire à des moments différents.

Toutefois, les transactions doivent toujours être utilisées.Le flux de travail est correct (environ):

using (var session = factory.OpenSession()) 
using (var tx = session.BeginTransaction()) 
{ 
    //create and manipulate objects 
    session.Save(newObjectToBePersisted); 
    tx.Commit(); 
} 
+0

Merci Diego, ça répond parfaitement à ma question! –

0

Je ne sais pas avec certitude, mais c'est peut-être à cause des clés primaires. Lorsque vous enregistrez deux objets Trancident et que vous utilisez Identity comme modèle de génération de clé primaire, Nhibernate ne connaît pas les ID de la table de jointure plusieurs-à-plusieurs. Dans l'utilisation des mots, vous devriez toujours envelopper toutes les manipulations avec des entités dans les transactions. Lorsque vous validez la transaction, toutes les modifications seront transférées dans la base de données. Et avant de le commettre, pourquoi essaieriez-vous de sélectionner l'entité déjà sélectionnée?

0

Utilisez-vous le mode de rinçage manuel? Si vous l'avez mis en automatique, il le fera dès que nécessaire. Si vous courez dans une transaction, vous devez faire session.getTransaction().commit() pour vous assurer que le changement demeure. Hibernate videra la session avant d'exécuter une requête qui pourrait avoir le mauvais résultat sinon, ou avant de valider la transaction.

Vous pouvez configurer Hibernate pour enregistrer une collection d'objets enfants lorsque le parent est enregistré. Lisez la section sur la persistance transitive (sur la page de doc lien ci-dessous, dans les commentaires)

(Disclaimer: J'utilise Mise en veille prolongée java, pas NHibernate)

+0

Documentation expliquant mise en veille prolongée modes de chasse est ici: http://docs.jboss.org/hibernate/stable/core/reference/en/html/objectstate.html#objectstate- flush – RMorrisey