NHibernate: свойства родительского списка и связанные дочерние свойства не синхронизированы - PullRequest
0 голосов
/ 27 ноября 2009

У меня есть два связанных объекта: ProgramSession и ProgramTask, с отношением один ко многим. ProgramSession имеет много программных задач. Итак, объекты выглядят так:

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; }
    }
}

И сопоставления ...

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" />

Проблемы начинаются, когда я пытаюсь изменить ProgramSession для ProgramTask.

Если я удалю ProgramTask из свойства списка ProgramSession.ProgramTasks старого сеанса, а затем добавлю его к тому же свойству в новом сеансе, NHibernate сообщит мне, что удаленный объект будет восстановлен.

Если я просто изменю значение объекта ProgramTask.ProgramSession, у меня не возникнет проблем с сохранением. Однако я получаю странное поведение, если не сохраняю сразу, потому что свойства ProgramSession.ProgramTasks (в обоих сеансах) не синхронизируются до тех пор, пока не обновится сеанс NHibernate.

Изменение объекта ProgramTask.ProgramSession без непосредственного изменения списков также создает недопустимое состояние. Возьмите следующий код в качестве примера:

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

Это более проблематично в коде, который выполняется позже, при котором предполагается, что коллекции ProgramTasks синхронизируются со свойством ProgramSession. Например:

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

Один из способов, который я использовал для обхода этого, был запрос к списку. Я не могу использовать его везде, и это явно плохое решение, но оно подчеркивает проблему:

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

Есть ли способ справиться с такой ситуацией? Лучшая практика? Я делаю что-то неправильно? Является ли отображение неверным? Есть ли какой-то сверхсекретный флаг NHibernate, который мне нужно установить?

1 Ответ

1 голос
/ 27 ноября 2009

Не уверен, что я все понимаю, что вы здесь делаете. Некоторые мысли:

Если вы решите переместить ProgramTasks вокруг, тогда они станут независимыми и не должны отображаться с помощью cascade="all-delete-orphan". Если вы сделаете это, NH удалит ProgramTask из базы данных, когда вы удалите его из ProgramSession.

Отобразите карту, используя cascade="none", и управляйте жизненным циклом объекта самостоятельно. (это означает: сохраните его до того, как ProgramSession будет сохранено. Удалите его, когда он больше не используется.)

Не уверен, что это тоже проблема, но учтите, что если у вас обратная ссылка, ваш код отвечает за согласованность ссылок. Конечно, ссылки очищаются после сохранения в базе данных и загрузки в пустой сеанс, потому что в базе данных есть только один внешний ключ. Но это не так, как это должно быть сделано. NH не несет ответственности за управление вашими ссылками. (Его единственная обязанность - сохранять то, что вы делаете в памяти.) Поэтому вам нужно сделать это согласованным в памяти и реализовать свою бизнес-логику так, как если бы не было NHibernate.

...