2010-06-22 4 views
1

J'ai un objet où je maintiens une relation à un autre objet:Utilisation d'objets temporaires provoque l'exception transitoire Objet

public class Foo { 
    public Bar Bar { get; set; } 
} 

Dans la cartographie, je référence à Bar que je peux maintenir la relation - Je ne veux pas objet parent de mettre à jour les propriétés de l'enfant, juste l'existence de la relation:

References(x => x.Bar, "BarId") 
    .Cascade.None(); 

dans la couche d'interface utilisateur que je crée la relation à l'aide d'une propriété qui n'est pas la clé primaire sous-jacente:

item.Bar = new Bar { Code = "123" }; 

Dans la couche dépôt I hydrate l'objet si elle ne possède pas la clé primaire peuplée:

if(item.Bar.Id == null) 
{ 
    item.Bar = barRepository.RetrieveByCode(item.Bar.Code); 
} 

Quand je la ligne de RetrieveByCode Runs (qui est un Criteria.UniqueResult sous les couvertures) je reçois une exception TransientObjectException m'indique que "l'objet référence une instance transitoire non enregistrée - enregistre l'instance transitoire avant le vidage" pour le type Bar.

Lorsque je cours le même chemin de code sans créer l'objet Bar temporaire cela fonctionne. Il semble que la barre créée en tant qu'oject temporaire soit suivie par NHibernate, mais je veux qu'elle oublie qu'elle ait jamais existé car elle n'est qu'un espace réservé.

Avez-vous des idées pour y parvenir?

MISE À JOUR: En effectuant d'autres tests, il semble que le suivi des modifications dans Foo cause des problèmes. Si j'appelle Session.Evict (item) après l'avoir récupéré, mais avant de faire des changements, puis de rattacher l'objet en utilisant Session.Update (item) après que je l'ai fait, il semble fonctionner, mais il met à jour les objets enfants qui ne sont pas ce que je veux - je veux seulement gérer la relation.

MISE À JOUR 2: J'ai changé le FlushMode d'Auto à Commit. Il semble avoir désactivé la mise en file d'attente de tout changement temporaire de l'objet. Après avoir étudié le comportement de NH un peu plus loin, il semble que Update fonctionne plus comme un appel de «réattachement» plutôt que comme un appel explicite de «mise à jour immédiate».

MISE À JOUR 3: Il semble avoir changé FlushMode a causé d'autres problèmes avec des transactions qui nécessitaient plusieurs étapes opérationnelles. Je suis retourné pour essayer une autre approche:

if(item.Bar.Id == null) 
{ 
    var barCode = item.Bar.Code; 
    item.Bar = null; 
    item.Bar = barRepository.RetrieveByCode(barCode); 
} 

Répondre

0

Pourquoi voulez-vous que cela fonctionne comme ça? Pourquoi ne pas simplement mettre item.Bar en utilisant l'objet Bar récupéré:

item.Bar = barRepository.RetrieveByCode("123"); 

Vous pourriez être en mesure de faire votre travail de motif à l'aide Load:

if(item.Bar.Id == null) 
{ 
    var bar = barRepository.RetrieveByCode(item.Bar.Code); 
    item.Bar = session.Load<Bar>(bar.Id); 
} 
+0

La couche d'interface utilisateur ne se préoccupe pas de la façon dont la l'objet est persisté. Il dit au service de domaine de créer une relation entre Foo et Bar. Le service de domaine appelle les différents référentiels pour hydrater les objets appropriés. Le défi avec votre exemple de chargement est que le TransientObjectException est levé pendant RetrieveByCode quand il essaye d'appeler Criteria.UniqueResult, ainsi je n'obtiendrai pas à l'appel de charge. –

+0

Les référentiels devraient partager un seul ISession afin qu'ils puissent participer à la transaction.Je ne comprends pas pourquoi une requête critère jette cette exception; pouvez-vous poster le code? –

+0

Il se lance probablement parce qu'il roule et trouve cet objet Bar faux référencé. S'il était en cascade, il conserverait une nouvelle instance. L'utilisation entière est erronée. –

Questions connexes