NHibernate - дублировать результаты при использовании кэша коллекции

Я получаю очень странное поведение от NHibernate, когда использую кэш второго уровня с несколькими уровнями двухсторонних отношений родитель-ребенок (-grandchild) один-ко-многим:

int id;

using(var session = sessionFactory.OpenSession())
{
    var parent = new Parent();
    var child1 = parent.AddChild();
    child1.AddGrandChild();
    var child2 = parent.AddChild();
    child2.AddGrandChild();
    session.Save(parent);
    session.Flush(); // force id generation
    id = parent.Id;
}

using(var session = sessionFactory.OpenSession())
{
    var parent = session.Get<Parent>(id);
    parent.Children.Should().HaveCount(2); // but is actually 3; second child duplicated
}

Второй дочерний элемент, имеющий двух внуков, дублируется в коллекции, но с тем же идентификатором объекта (ReferenceEquals() является true). Когда я отключаю кеширование для Parent.Children или установите стратегию извлечения в Joinпроблема уходит. Есть идеи как узнать что здесь происходит?

Объекты:

class Parent
{
    public virtual int Id { get; protected set; }
    public virtual List<Child> children = new List<Child>();
    public virtual IEnumerable<Child> Children
    {
        get { return children.ToList(); }
    }

    public virtual Child AddChild()
    {
        var child = new Child(this);
        this.children.Add(child);
        return child;
    }
}

class Child
{
    public Child(Parent parent)
    {
        this.Parent = parent;
    }

    public virtual int Id { get; protected set; }
    public virtual List<GrandChild> grandChildren = new List<GrandChild>();
    public virtual IEnumerable<GrandChild> GrandChildren
    {
        get { return grandChildren.ToList(); }
    }

    public virtual Parent Parent { get; protected set; }

    public virtual GrandChild AddGrandChild()
    {
        var grandChild = new GrandChild(this);
        this.grandChildren.Add(grandChild);
        return grandChild;
    }

}

class GrandChild
{
    public virtual int Id { get; protected set; }
    public virtual Child Parent { get; protected set; }

    public GrandChild(Child parent)
    {
        this.Parent = parent;
    }

}

Отображения:

public class ParentMap : ClassMap<Parent>
{
    public ParentMap()
    {
        Id(p => p.Id).GeneratedBy.Identity();
        HasMany(p => p.Children)
            .Access.CamelCaseField()
            .Inverse()
            .Cascade.AllDeleteOrphan()
            .Cache.ReadWrite();
        Cache.ReadWrite();
    }
}

public class ChildMap : ClassMap<Child>
{
    public ChildMap()
    {
        Id(c => c.Id).GeneratedBy.Identity();
        HasMany(c => c.GrandChildren)
            .Access.CamelCaseField()
            .Inverse()
            .Cascade.AllDeleteOrphan()
            .Cache.ReadWrite();
        References(c => c.Parent);
        Cache.ReadWrite();
    }
}

public class GrandChildMap : ClassMap<GrandChild>
{
    public GrandChildMap()
    {
        Id(c => c.Id).GeneratedBy.Identity();
        References(c => c.Parent);
        Cache.ReadWrite();
    }
}

[РЕДАКТИРОВАТЬ]

Я обошел эту проблему, не включив кэш для дочерних коллекций. Так как я сделал это в первую очередь, чтобы избежать N+1, выберите проблемы с fetch join запросы на дочерние элементы кэшированных объектов, я сделал следующее:

    public ChildMap()
    {
       // ...
        HasMany(c => c.GrandChildren) // removed Cache.ReadWrite() here
            /* ... */;

        // added IncludeAll() to make sure lazily fetched collections get cached
        Cache.ReadWrite().IncludeAll(); 
    }

Я до сих пор не понимаю, что здесь происходит, поэтому любое понимание этого вопроса будет приветствоваться:-).

1 ответ

Пытались ли вы использовать транзакции вместо промывки? подобно

using(var session = sessionFactory.OpenSession())
using(var transaction = session.BeginTransaction())
{
    var parent = new Parent();
    [...]
    parent.Save();
    transaction.Commit();
    id = parent.Id;
}

Может быть, это помогает. Однажды у меня была похожая проблема, которую я мог решить с помощью транзакций.

Другие вопросы по тегам