11
votes

Nibernate fluide-Nibernate Beaucoup de Cascade ne remplit pas la table de liens

OK, peu importe la façon dont je définis ces mappages, ma cartographie plusieurs à plusieurs personnes ne veut pas fonctionner avec une insertion en cascade. J'ai essayé diverses combinaisons de cascade () code> avec inverse () code> et en supprimant toutes les propriétés inutiles pour comprendre s'ils avaient quelque chose à voir avec cela ne fonctionnant pas, mais pas de verrouillage.

C'est vraiment simple: j'ai un message code> (comme un email) envoyé à partir d'un utilisateur (j'ai appelé l'entité basicuser code>) à un certain nombre de Utilisateurs (via la propriété à code>). Utilisateur CODE> et Message Code> en termes de destinataires a une relation de plusieurs à plusieurs mais fromUser code> a un à plusieurs. FromUser fonctionne bien et il est mis à jour d'accord mais mon problème est avec plusieurs à plusieurs. J'ai même supprimé deuser code> et relation juste pour vérifier si c'était le problème, mais n'a pas aidé. P>

Voici donc la conception de la table (avoir supprimé la relation de de code> à basicuser code> pour la simplicité) p>

Entrez la description de l'image Ici p>

et voici les mappages: p> xxx pré>

et j'appelle cela et cela ne fonctionne pas (tableau basiqueReMersage code> ne va pas peupler): (Notez que les utilisateurs avec ID 1, 2 et 3 existent - j'ai également essayé de les obtenir de la base de données, puis d'ajouter à la liste ne fonctionnant toujours pas) P>

ISessionFactory factory = GetSessionFactory();
ISession session = factory.OpenSession();
Message m = new Message()
                {
                    Body = "Please note 2",
                    Subject = "Secret 2",
                    From = new BasicUser(){Id = 2},
                    SentAt = DateTime.Now,
                };
m.To.Add(new BasicUser(){Id = 1});
m.To.Add(new BasicUser(){Id=3});
session.SaveOrUpdate(m);
session.Close();


0 commentaires

4 Réponses :


5
votes

Vous avez fait des deux références inverse. Cela signifie à NH: ne le stockez pas de ce côté, car il est déjà stocké par l'autre côté. Si les deux sont inverse, rien n'est stocké.

supprimer inverse de l'une des références.


3 commentaires

J'ai testé toutes sortes d'allllllllllllllll. J'ai testé avec un Invers () Mais vous avez raison, pour la question, il doit être propre et je l'ai supprimé.


Il semble que j'avais oublié de supprimer le inverse () . J'ai enlevé le supplément.


Et les deux références sont-elles cohérentes en mémoire? NH stocke ce que vous avez en mémoire, et s'il est incompatible, vous obtenez des résultats étranges.



4
votes

Vous devez envelopper votre code en transaction. Sinon, NHibernate ne économisera pas de valeurs dans la table de jonction


8 commentaires

Votre réponse est fausse. Cela n'a rien à voir avec les transactions ... veuillez le supprimer.


Avez-vous essayé ce qu'il a suggéré? L'absence d'une transaction est souvent la cause de ce type de problèmes. En outre, une réponse incorrecte n'a pas besoin d'être supprimée (et peut être utile pour d'autres personnes qui rencontrent cette question à une date ultérieure).


J'ai répondu à cela non seulement pour répondre. J'ai eu un problème et une transaction similaires a aidé ...


@James, existe-t-il un exemple de travail de relation de plusieurs à plusieurs, qui met à jour la table commune? Si oui, pouvez-vous me signaler?


@Sly, merci. Eh bien, vous avez raison - dans un scénario monde réel, je l'ai utilisé une transaction. Mais le fait que NHibernate nécessiterait une opération de travail me confond vraiment. :( Pour être franc, je suis vraiment déçu par obtenir NH.


:) Eh bien, je souhaite. Si seulement cela aurait résolu mon problème. Je suis surpris, tout le monde pourrait me signaler à un exemple de travail?


Sly a raison. Cela a fonctionné pour moi lorsque je l'ai enveloppé dans une transaction. Assurez-vous de commettre votre transaction à la fin de la portée. Considérez cet exemple, tables chantillant et personne . Les nombreux tableaux ont été appelés chansitePerson et contenaient deux colonnes: chanson d'emploi et PersonID . Contrairement à votre exemple, j'ai utilisé la cascade des deux côtés, je ne sais pas si cela compte. Semblable à votre exemple, j'avais inverse d'un côté et spécifié le nom de la table. Contrairement à votre exemple, je n'ai pas spécifié le parentkeyColumn / ChildkeyColumn, les paramètres par défaut ont fonctionné. Ne soyez pas découragé, NHibernate est excellent si elle est protégée correctement.


Pas complètement vrai: session.flush () est absolument suffisant pour gérer les enregistrements d'enfants qui vont avec l'entité principale. Depuis que itransaction.commit fait la même chose sous le capot, il est correct d'utiliser (et la sécurité des transactions est, BTW, un bon addenda de toute façon)



0
votes

Vous devez rendre les objets de baseAuser persistants:

ISessionFactory factory = GetSessionFactory();
ISession session = factory.OpenSession();
Message m = new Message()
                {
                    Body = "Please note 2",
                    Subject = "Secret 2",
                    From = new BasicUser(){Id = 2},
                    SentAt = DateTime.Now,
                };
var basicUser1 = new BasicUser(){Id = 1};
session.Save(basicUser1);
m.To.Add(basicUser1);
var basicUser3 = new BasicUser(){Id = 3};
session.Save(basicUser3);
m.To.Add(basicUser3);
session.Save(m);
session.Flush();


4 commentaires

Salut Jamie, comme je l'ai mentionné, la base de données contient des identifiants de base de 1, 2 et 3. Ils sont déjà dans la base de données.


C'est un harnais simplifié, pas un référentiel. Bien entendu, dans le motif de référentiel, j'aurais une iunitofwork qui serait créée dans un en utilisant la déclaration .


Votre code crée de nouveaux basiques, ne les récupérant pas de la base de données. Si vous avez essayé de les obtenir de la base de données, ce sont vos paramètres inverse, comme dit Stefan.


Je l'ai fait de cette façon aussi. Il suffit de lire attentivement la question, n'est-ce pas?



6
votes

La réponse à propos des transactions est correcte-accidentelle-occurrence. L'occurrence correcte est également correcte, c'est que cela se manifeste comme tel, car vous utilisez quelque chose comme un générateur identité qui nécessite un voyage de base de données sur Enregistrer pour obtenir l'identité.

Voici ce que NHibernate fait lorsque vous définissez un Save-update cascade (ou une cascade qui implique que) sur une association nombreuses à plusieurs:

Enregistrez l'entité mère. Cela va immédiatement à la base de données à cause de la stratégie d'identité. La collection est "modifiée" (car c'est nouveau), alors regardons ses membres. Cette étape ne se produit que si inverse n'est pas défini sur la cartographie du parent de la relation. Créez une entrée dans la table de liens pour chacun d'eux.

mais attendez, certaines de ces entrées sont transitoires. Les cascades sont correctement définies, c'est bon - mais afin de créer l'entrée de la table de liens dans la session, nous avons besoin de l'identifiant de ces enfants, alors sauveons-les immédiatement.

Maintenant, toutes les entités pertinentes sont persistantes et la session a un inséré en attente pour toutes les entrées de la table de liaison. Flushing La session émettra les commandes et créera ces entrées.

Lorsque vous enveloppez votre code dans une transaction, commettez la transaction affleurant la session, de sorte que cela est créé lorsque vous vous engagez. Si vous utilisez un générateur d'identité qui ne nécessite pas de rond-aller-retour de DB, les entrées de la table de liaison et les entités sont toutes insérées en même temps, de sorte que vous ne verrez pas la "déconnexion" que vous voyez - si La session n'est jamais rinçue, rien n'est jamais inséré, et quand il est rincé, tout est inséré. Si vous n'avez aucune de ces choses, rincer votre session explicitement créera les entrées de la table de liaison et tout ira bien.


0 commentaires