NHibernate SaveOrUpdate Enfant Collection Pas Mis À Jour Avec L'Identité Id
Je suis clairement en manque de quelque chose (j'espère évident), et j'ai pas eu de chance avec Google à ce jour.
J'ai une relation Parent-Enfant assignés comme suit
Simplifié De La Carte Mère
public sealed class ParentMap : ClassMap<ParentEntity>
{
public ParentMap()
{
Table("Parent");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.ServeralNotNullableProperties).Not.Nullable();
HasMany(x => x.Children).KeyColumn("ChildId")
.Inverse()
.LazyLoad()
.Cascade
.AllDeleteOrphan();
References(x => x.SomeUnrelatedLookupColumn).Column("LookupColumnId").Not.Nullable();
}
}
Simplifié Enfant Carte
public sealed class ChildMap : ClassMap<ChildEntity>
{
public ChildMap()
{
Table("Child");
Component(x => x.Thumbprint);
Id(x => x.Id).GeneratedBy.Identity();
Map(x => x.MoreNotNullableProperties).Not.Nullable();
References(x => x.Parent).Column("ParentId").Not.Nullable();
}
}
De Services Simplifiée Des Étapes De Méthode
J'ai ensuite une méthode de service qui récupère Parent et ajoute une nouvelle Enfant par le biais de certaines méthode de domaine. Le sous-jacent NHibernate code se résume à:
1) Session Ouverte sur WCF AfterReceiveRequest (IDispatchMessageInspector)
_sessionFactory.OpenSession();
2) Récupérer l'instance existante de parent via .Requête
_session.Query<ParentEntity>()
.Where(item => item.Id == parentId)
.Fetch(item => item.SomeLookupColumn)
.First();
3) Ajouter une nouvelle "Enfant" entité "Mère" par domaine de méthode de l'objet comme...
public ChildEntity CreateChild()
{
var child = new ChildEntity{ Parent = this };
Children.Add(child);
return child;
}
4) Finalement, les appels SaveOrUpdate sur "Parent" de l'entité.
//ChildEntity Id is 0
_session.SaveOrUpdate(parentEntity)
//Expect ChildEntity Id to NOT be 0
Remarque: l'Utilisation de SaveOrUpdate Ne conserver des modifications apportées à la base de données; l'utilisation de Fusionner les résultats dans TransientObjectException mentionnés ci-dessous.
5) Enfin, la transaction validée sur WCF BeforeSendReply (IDispatchMessageInspector)
_session.Commit();
Le Problème
En général, lorsqu'une entité est enregistrée, après l'appel à SaveOrUpdate, l'Identifiant de cette entité refects l'Identité générée par l'instruction INSERT. Cependant, lorsque j'ajoute une nouvelle entité enfant à un parent, l'entité associée dans Children
n'est pas assigné un numéro d'identification. J'ai besoin de passer cet Id à l'appelant ainsi les appels suivants résultat des MISES à jour et pas des INSERTS supplémentaires.
Pourquoi est NHibernate pas la mise à jour de l'entité sous-jacente?
Je ne explicitement appel SaveOrUpdate sur l'enfant (qui suce si c'est le cas)?
Toute réflexion sur la question grandement apprécié. Merci!
MODIFIER
Je tiens à souligner, que la nouvelle entité enfant EST enregistré comme prévu; je n'arrive pas à récupérer l'Id affecté.
Mise à JOUR
Essayé de commutation .De fusion(~) comme suggéré par Michael Buen ci-dessous; résultant en une TransientObjectException de me dire pour enregistrer explicitement modifié mon enfant entité avant l'appel à la fusion. J'ai également expérimenté avec .Persist(~) en vain. Toute autre vision grandement apprécié.
objet est sauvegardé transitoire exemple - pour enregistrer l'instance transitoire avant la fusion: Mon.Espace de noms.ChildEntity
OriginalL'auteur Chris Baxter | 2011-04-12
Vous devez vous connecter pour publier un commentaire.
J'ai enfin trouvé le temps de creuser autour de la NHibernate code... la raison de ce qui se passe de sens... bref, la réponse - la Cascade, les actions sont traitées sur la Session.Commit(); eh bien, après le service ci-dessus, l'opération est terminée. Donc, mon enfant, les objets n'ont pas été actualisés pour refléter l'attribuée ids par le temps, le service méthode retourne la mise à jour de l'entité enfant.
S'avère que je doit appeler SaveOrUpdate directement sur l'entité enfant si j'ai besoin de connaître le numéro d'identification immédiatement.
OriginalL'auteur Chris Baxter
Pour la maison d'scénario, l'utilisation de Fusion(anciennement connu sous le SaveOrUpdateCopy)
Exemple: http://www.ienablemuch.com/2011/01/nhibernate-saves-your-whole-object.html
Sujet:
Vous n'en avez pas besoin, en effet, un ORM comme NHibernate brille, il peut économiser de l'ensemble de l'objet graphique, et il résout vraiment la différence d'impédance entre l'Objet et la base de données.
La physique mise en œuvre(par exemple, int ou guid) de la façon dont un parent et son enfant des dossiers(et sous-enregistrements enfants et ainsi de suite) sont liés est complètement invisible à partir de l'app. Vous pouvez se concentrer sur vos objets plutôt que de les sous-le-capot de plomberie sur quels types de données(int,guid,etc) de vos relations d'objet doit utiliser
[Mise à JOUR]
Vous pouvez encore sauver la mère et de l'épargne en cascade pour les enfants, et peut amener l'enfant de l'id de trop. Si vous avez besoin pour obtenir l'id d'enfant, qu'après validation.
Vous ne pouvez pas obtenir l'id d'enfant de cette façon:
Doit ce faire:
Parlé un peu trop vite; Commit(), j'obtiens un TransientObjectException 'objet fait référence à un non enregistrées transitoire exemple - pour enregistrer l'instance éphémère avant de rincer.' ???
Mettre Inverse(qui je pense doit être la valeur par défaut) attribut sur votre HasMany cartographie
Malheureusement, l'Inverse est déjà défini dans la cartographie (voir ParentMap ci-dessus).
Ne vous arrive de stocker les _session variable statique? Peut-être que NHibernate cache un objet(d'où la chose transitoire erreurs) si la session est instancié comme statique. Seul le _sessionFactory doit rester statique
OriginalL'auteur Michael Buen
Peut-être que cela aidera (C'est à propos d'attribut Inverse):
http://www.emadashi.com/index.php/2008/08/nhibernate-inverse-attribute/
OriginalL'auteur VikciaR
On pourrait appeler
session.Flush()
, qui effectue les insère sur la base de données. Ce n'est pas l'idéal à cause de l'impact sur la performance.OriginalL'auteur Stefan Steinegger