Карта NHibernate по коду с ассоциацией OneToMany: выбор неэффективен, вставки не выполняются (NHibernate.StaleStateException) - PullRequest
0 голосов
/ 30 ноября 2018

У меня есть родительский класс и дочерний класс.Один ребенок всегда связан только с одним родителем, но у родителя может быть несколько детей:

public class Parent
{
    public virtual string Id { get; set; }
    public virtual string Name { get; set; }

    public virtual IList<Child> Children { get; set; } = new List<Child>();
}

public class Child
{
    public virtual int Id { get; set; }
    public virtual string ParentId { get; set; }
    public virtual string Name { get; set; }
}

Я использую последнюю версию NHibernate 5.1.3 и сопоставляю по коду:

internal class ParentMapping : ClassMapping<Parent>
{
    public ParentMapping()
    {
        Table("Parent");

        Id(x => x.Id);
        Property(x => x.Name);

        Bag(
            x => x.Children,
            map =>
            {
                map.Key(km => km.Column("ParentId"));
                map.Lazy(CollectionLazy.NoLazy);
                map.Cascade(Cascade.Persist);
                map.Inverse(true);
            },
            x => x.OneToMany());
    }
}

internal class ChildMapping : ClassMapping<Child>
{
    public ChildMapping()
    {
        Table("Child");

        Id(x => x.Id, x => x.Generator(Generators.Identity));
        Property(x => x.ParentId);
        Property(x => x.Name);
    }
}

Запросы работают, но довольно неэффективны.Вместо создания единственного оператора JOIN для запроса дочерних элементов вместе с их родителями, выполняется явный SELECT для извлечения дочерних объектов.

Еще хуже, вставки приводят к следующей ошибке:

NHibernate.StaleStateException: 'Batch update returned unexpected row count from update; actual row count: 0; expected: 3'

Вот пример запроса:

using (var session = _sessionProvider.GetSession())
    return session.Query<T>().ToList();

И вот код для сохранения нового элемента:

using (var session = _sessionProvider.GetSession())
{
    session.Transaction.Begin();
    session.Save(newEntity);
    session.Transaction.Commit();
}

Так что все довольно просто.

Я полагаю, конфигурация Bag () в ParentMapping должна быть исправлена.Что я делаю не так?

1 Ответ

0 голосов
/ 30 ноября 2018

Изменение стратегии выборки для сопоставления мешков для присоединения сгенерирует запрос на объединение, например:

Bag(
    e => e.Children,
    map => {
        map.Key(km => km.Column("ParentId"));
        // map.Lazy(CollectionLazy.NoLazy);
        // change fetch str
        map.Fetch(CollectionFetchMode.Join);
        map.Cascade(Cascade.Persist);
        map.Inverse(true);
    },
    x => x.OneToMany()
);

И у вас есть коллекция, сохраняемая как обратная (map.Inverse(true);), у вас должно быть многона одно отображение для Parent в вашем Child классе, например:

public class Child {
    public virtual int Id { get; set; }
    // public virtual string ParentId { get; set; }
    public virtual Parent Parent { get; set; }
    public virtual string Name { get; set; }
}

Затем сопоставьте свойство Parent как ManyToOne, например:

public ChildMapping() {
    // other mapping goes here
    ManyToOne(
        x => x.Parent,
        map => {
            map.Column("ParentId");
            map.Class(typeof(Parent));
            map.Fetch(FetchKind.Join);
        }
    );
}

Но nhibernateне включайте дочерние элементы родительского по умолчанию (может быть, это слишком тяжело), ​​и если вы хотите запросить дочерние элементы с родительским экземпляром, вы можете сделать запрос следующим образом:

using (var session = OpenSession()) {
    var query = session.Query<Parent>().Select(p => new {
        Parent = p, Children = p.Children
    });
    var data = query.ToList();
}

Для сохранения сущностей в базе данных, следует сделатькак это:

try {
    // save parent first
    var parent = new Parent();
    parent.Name = "Parent object";
    session.Save(parent);
    // then save child
    var child = new Child();
    child.Name = "Child object";
    child.Parent = parent;
    session.Save(child);
    session.Flush();
    tx.Commit();

}
catch (Exception) {
    tx.Rollback();
    throw;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...