Nhibernate Self-reference Mapping

0

Hello, I need to return a list of child objects of the same type as the parent. however, using nhibernate, the same only returns a child object, while in the database I have 3 children. Here are some excerpts from the code:

Data Step

    public Etapa ObterPorId(int id, bool completo = false)
    {
        if (!completo) return base.ObterPorId(id);
        using (var session = HibernateUtil.GetSessionFactory().OpenSession())
        {
            return session.Query<Etapa>()
                //.Fetch(e => e.EtapaFilhas) // já tentei com este tb..
                .FetchMany(e => e.EtapaFilhas).FirstOrDefault(e => e.Id == id);
        }
    }

StepMap:

public class EtapaMap:ClassMap<Etapa>
{
    public EtapaMap()
    {   
        Table("TEMA_ETAPA");
        Not.LazyLoad();

        Id(i => i.Id, "id").GeneratedBy.Identity();

        HasMany(e => e.EtapaFilhas)
        .Cascade.DeleteOrphan().KeyColumn("id_TEMA_ETAPA_pai");

        References(e => e.EtapaPai).Column("id_TEMA_ETAPA_pai");
        References(e => e.Tema).Column("id_TEMA_FORMULARIO");
    }
}

Step (entity)

public class Etapa
{
    public virtual int Id { get; set; }
    public virtual Etapa EtapaPai { get; set; }
    public virtual Tema Tema { get; set; }
    public virtual ISet<Etapa> EtapaFilhas { get; set; }

}

Test Method:

        [Test]
        public void DeveRetornarQuantidadeDeFilhas()
        {
            var etapaPaiId = 13;

            var sut = new EtapaDados();

            var result = sut.ObterPorId(etapaPaiId, true).EtapaFilhas;

            Assert.That(result.Count, Is.EqualTo(3));
        }

Using LinqPad or EF, it returns 3 children. I think I may be wrong in mapping or in the data call method, but I do not know how to fix it.

Alternatively, I've created a method that returns only children. However I wanted to avoid this approach, since I should access your children through the ISet<Etapa> EtapaFilhas property:

    public IEnumerable<Etapa> ObterFilhas(int idEtapaPai)
    {
        using (var session = 
        HibernateUtil.GetSessionFactory().OpenSession())
            return session.Query<Etapa>()
                .Where(e => e.EtapaPai.Id == idEtapaPai)
                .ToList();
    }
    
asked by anonymous 17.05.2017 / 03:39

1 answer

0

To solve this problem, I found two valid approaches:

Where().FetchMany().Single()

or

Where().FetchMany().AsEnumerable().FirstOrDefault()

The problem is that First() and its variations propagate a select top 1 by limiting the result of the query.

Practical solution:

    public Etapa ObterPorId(int id, bool completo = false)
    {
        if (!completo) return base.ObterPorId(id);
        using (var session = HibernateUtil.GetSessionFactory().OpenSession())
        {
            var approachOne = session.Query<Etapa>()
                .Where(e => e.Id == id)
                .Fetch(e => e.EtapaFilhas)
                .Single();

            var approachTwo = session.Query<Etapa>()
                .Fetch(e => e.EtapaFilhas).AsEnumerable()
                .FirstOrDefault(e => e.Id == id);

            return approachOne;
        }
    }

AsEnumerable ()

As Dr Gabriel wrote. Schenker, and Aaron Cure in their NHibernate 3 Beginner's Guide, the " AsEnumerable " statement is used to switch the context from [LINQ to NHibernate to LINQ to objects] without triggering query execution.

Now, whenever iterates over the query result, the LINQ provider knows which part of the expression tree to take and convert to an SQL statement, which can be executed from the database .

I also suggest stack NHibernate: Why does Linq First () force only one item in all child and grandchild collections with FetchMany () .

    
17.05.2017 / 19:09