NHibernate: les propriétés de la liste parente et les propriétés enfants associées ne sont pas synchronisées

StackOverflow https://stackoverflow.com/questions/1809032

Question

J'ai deux objets liés: ProgramSession et ProgramTask, avec une relation un à plusieurs. Une ProgramSession a de nombreuses ProgramTasks. Ainsi, les objets ressemblent à ceci:

public class ProgramSession
{
    public virtual IList<ProgramTask> ProgramTasks
    {
        get { return _programTasks; }
        set { _programTasks = value; }
    }
}

public class ProgramTask
{
    public virtual ProgramSession ProgramSession
    {
        get { return _programSession; }
        set { _programSession = value; }
    }
}

Et les mappages ...

ProgramSession.hbm.xml

<bag name="ProgramTasks" lazy="false" cascade="all-delete-orphan" inverse="true" >
    <key column="SessionUid"></key>
    <one-to-many class="ProgramTask"></one-to-many>
</bag>

ProgramTask.hbm.xml

<many-to-one name="ProgramSession" column="SessionUid" class="ProgramSession" />

Les problèmes commencent lorsque j'essaie de modifier la session de programme d'une tâche de programme.

Si je supprime la ProgramTask de la propriété de liste ProgramSession.ProgramTasks de l'ancienne session, puis l'ajoute à la même propriété de la nouvelle session, NHibernate me dit que l'objet supprimé sera réenregistré.

Si je change simplement la valeur de l'objet ProgramTask.ProgramSession, je n'ai aucun problème à enregistrer. Cependant, mon comportement est bizarre si je ne sauvegarde pas immédiatement car les propriétés ProgramSession.ProgramTasks (sur les deux sessions) ne sont pas synchronisées avant l'actualisation de la session NHibernate.

La modification de l'objet ProgramTask.ProgramSession sans modifier directement les listes également crée un état non valide. Prenez le code suivant comme exemple:

programTask.ProgramSession = newProgramSession;
Assert.That(newProgramSession.ProgramTasks.Contains(programTask)); // fails
Assert.That(!oldProgramSession.ProgramTasks.Contains(programTask)); // fails

Ceci est plus problématique dans le code exécuté ultérieurement, qui suppose que les collections ProgramTasks sont synchronisées avec la propriété ProgramSession. Par exemple:

foreach(var programTask in programSession.ProgramTasks)
{
    // whatever
}

Un hack avec lequel j’avais l'habitude de travailler était d'interroger la liste. Je ne peux pas l'utiliser partout, et c'est clairement une mauvaise solution, mais cela souligne le problème:

var tasksActuallyInSession =
    programSession.ProgramTasks
        .Where(task => task.ProgramSession == programSession)
        .ToList();

Existe-t-il un moyen de gérer ce genre de situation? Une meilleure pratique? Est-ce que je fais quelque chose de mal? Le mappage est-il incorrect? Y a-t-il un indicateur NHibernate super secret à définir?

Était-ce utile?

La solution

Je ne sais pas si je comprends tout ce que vous faites ici. Quelques réflexions:

Si vous décidez de déplacer ProgramTasks , ils deviennent indépendants et ne doivent pas être mappés à l'aide de cascade = "all-delete-orphan". . Si vous procédez ainsi, NH supprime la ProgramTask de la base de données lorsque vous le supprimez d'une ProgramSession .

Mappez-le à l'aide de cascade = " none " et contrôlez vous-même le cycle de vie de l'objet. (Cela signifie: stockez-le avant qu'un ProgramSession ne soit stocké. Supprimez-le lorsqu'il n'est plus utilisé.)

Vous n'êtes pas sûr qu'il s'agisse également d'un problème, mais notez que si vous avez une référence inverse, votre code est responsable de la cohérence des références. Bien sûr, les références sont nettoyées après le stockage dans la base de données et le chargement dans une session vide, car il n'y a qu'une seule clé étrangère dans la base de données. Mais ce n'est pas comme cela que cela devrait être fait. NH n’est pas responsable de la gestion de vos références. (Sa seule responsabilité est de conserver ce que vous faites en mémoire.) Vous devez donc la rendre cohérente en mémoire et mettre en œuvre votre logique métier comme s'il n'y avait pas de NHibernate derrière.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top