Как ссылаться на свойство ID в отношениях с NHibernate? - PullRequest
0 голосов
/ 13 октября 2011

Как мне отобразить отношения, где дочерняя конечная точка предоставляется через свойство Id, а не через весь родительский объект?

Вот пример:

class Parent {
    public Guid Id { get; set; }
    public List<Child> Chlidren { get; set; }
}

class Child {
    public Guid Id { get; set; }
    public Guid ParentId { get; set; }
}

Вот эквивалентные сопоставления, которые я использую:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Blabla"
                   namespace="Blabla"
                   auto-import="false">

    <typedef name="ChildrenList" class="Blabla" />

    <class name="Parent" table="Parent" lazy="false">
        <id name="Id" column="ID" type="Guid">
            <generator class="guid" />
        </id>

        <bag name="Children" table="Child"
                             cascade="save-update"
                             collection-type="ChildrenList"
                             lazy="false">
            <key column="ParentID" not-null="true" />
            <one-to-many class="Child" />
        </bag>
    </class>

    <class name="Child" table="Child" lazy="false">
        <id name="Id" column="ID" type="Guid">
            <generator class="guid" />
        </id>

        <!-- How to map ParentID here? -->
    </class>
</hibernate-mapping>

Когда я создаю родителя, добавляю несколько детей в коллекцию Children и затем сохраняю родителя, все в порядке. Но если сначала сохранить родительский объект, а затем создать дочерний объект, установив для его свойства ParentID идентификатор родительского объекта, то я получу

NHibernate.PropertyValueException:
not-null property references a null or transient value Child._Parent.ChildrenBackref

Все попытки сопоставить отношения many-to-one приводили к различным исключениям при создании конфигурации NHibernate. В основном о несоответствии типов объектов.

Я уверен, что NHibernate способен справиться с этим сценарием. Должно быть что-то довольно простое, что я скучаю.

EDIT:

Я думаю, что это имеет смысл для примера теста, который завершается неудачей с приведенным выше исключением:

var child = new Child(Create.Saved<Parent>().Id); // this sets the ParentId property
this.Repository.Save(child); // here I get the exception

Мои мысли, почему NHibernate поднимает это: Children свойство класса Parent, сопоставленное таким образом, что говорит, что ребенок не может существовать без родителя (<key column="ParentID" not-null="true" />). Когда я пытаюсь сохранить дочерний элемент, NHibernate пытается разрешить это отношение (найти родителя, к которому относится этот дочерний элемент) и завершается неудачей, поскольку в сопоставлении ему не предоставляется дочерняя конечная точка (которая в противном случае была бы ParentId свойством), он проверяет наличие его собственная Child._Parent.ChildrenBackref конечная точка, какой бы она ни была.

Это похоже на желаемое решение: отображение ParentId свойства как дочерней конечной точки отношения. Это заставит NHibernate разрешить родительский элемент, используя значение ParentId свойство в качестве первичного ключа родителя.

Дело в том, что я не знаю, возможно ли это.

1 Ответ

1 голос
/ 13 октября 2011

Отношения «один ко многим / многие к одному», которые у вас есть в NHibernate, всегда должны иметь доминирующую сторону (т. Е. Сторону, которая управляет «спасением»).

<bag name="Children" table="Child"
                     cascade="save-update"
                     collection-type="ChildrenList"
                     lazy="false">
    <key column="ParentID" not-null="true" />
    <one-to-many class="Child" />
</bag> 

Вышеотношения один-ко-многим, где доминирующей стороной является родитель.Это означает, что вы сохраняете родителя ... и это сначала спасет родителя, затем потомков (с нулевым ParentId), затем будет выпущено последующее обновление для установки child.ParentId.

Примечание:

Сначала вставляется дочерний элемент с ParentId = null ... если у вас есть ограничение в db или сопоставлении, чтобы сказать, что ParentId не может быть нулевым, это действие завершится неудачей.1011 * Обратите внимание на атрибут inverse = true .Это означает, что дочерний объект является доминирующим в отношениях, то есть дочерний объект отвечает.Родитель будет вставлен, затем идентификатор будет назначен child.ParentId, а затем дочерний элемент будет вставлен с уже установленным ParentId .

Во многих случаях, конечно,Вы хотите пойти в любую сторону.Самый простой способ сделать это - управлять отношениями на обоих концах (к сожалению, вы должны сделать это самостоятельно).

В Parent у вас есть метод:

public void AddChild(Child child)
{
   Children.Add(child);
   child.ParentId = Id;
}

public void RemoveChild(Child child)
{
    Children.Remove(child);
    child.ParentId = null;
}

Вкл.Дочерний, у вас есть метод:

public void SetParent(Parent parent)
{
    ParentId = parent.Id;
    parent.Children.Add(this);
}

Используя эти методы для добавления / удаления / установки, обе стороны остаются согласованными после выполнения действия.Таким образом, не имеет значения, устанавливаете ли вы inverse = true на сумке или нет.

см. http://www.nhforge.org/doc/nh/en/index.html#collections-example

...