Search code examples
c#sql-servernhibernatefluent-nhibernatequeryover

Get columns from Tables (Using Inner Join) with DetachedCriteria (prefereable) or QueryOver


I'm having a problem with my query in NHibernate With DetachedCriteria (or using Session QueryOver). I need to get only a few columns from each table, like the classes as follow:

public class PanelaCorrida : BaseEntity
{
    public virtual Int64? CodCorrida { get; set; }

    public virtual Int64 NumLocal { get; set; }

    public virtual Boolean IdcInspecionada { get; set; }

    public virtual String Sigla { get; set; }

    public virtual String Rota { get; set; }

    public virtual Local Local { get; set; }

    public virtual Panela Panela { get; set; }
}


public class Panela : BaseEntity
{
    public Panela()
    {
        this.Local = new Local();
        this.PanelaCorridas = new List<PanelaCorrida>();
    }

    public virtual Int32 Numero { get; set; }

    public virtual Boolean IdcAtiva { get; set; }

    public virtual Int16 Status { get; set; }

    public virtual ICollection<PanelaCorrida> PanelaCorridas { get; set; }

    public virtual Local Local { get; set; }

    #endregion
}


public class Local : BaseEntity
{
    public Local()
    {
        this.PanelaCorridas = new List<PanelaCorrida>();
        this.Panelas = new List<Panela>();
    }

    #region Property

    public virtual Int32 IdLocal { get; set; }

    public virtual Int32 AreaLocal { get; set; }

    public virtual String Descricao { get; set; }

    public virtual String Codigo { get; set; }

    #endregion
}

Basically, the Entity 'Panela' is the Mother of 'PanelaCorrida' (Each Panela can have multiple PanelaCorrida's) but a 'PanelaCorrida' can be in one Local. But one local can have multiple PanelaCorrida's as well. It's basically, this relationship:

Panela 1 - N PanelaCorrida

Local 1 - N Panela

Local 1 - N PanelaCorrida

For this query, i need to get the Last PanelaCorrida of the db, but i need the info of Panela and Local as well.

So far, i can get all data using this NHibernate query:

To get all id's of 'panela' which is active:

var panelaIdList = Session.QueryOver<Panela>()
                    .Select(c => c.Id)
                    .Where(c => c.IdcAtiva == true)
                    .List<Int64>();

To get all last id's of 'PanelaCorrida' which is active (and the last PanelaCorrida generated):

var corridaPanelaIdList = Session.QueryOver<PanelaCorrida>()
    .Select(
    Projections.Max<PanelaCorrida>(x => x.Id),
    Projections.Group<PanelaCorrida>(x => x.Panela)
    )
    .Where(p => p.Panela.IsIn(panelaIdList.ToArray()))
    .List<Object[]>();

Now, to get the result with all info of all those tables:

With DetachedCriteria:

criteria = DetachedCriteria.For<PanelaCorrida>()
    .CreateAlias("Local", "L")
    .CreateAlias("Panela", "P")
    .Add(Restrictions.In("Id", corridaPanelaIdList.Select(x => x[0]).ToArray()));

With Session QueryOver:

var corridas = Session.QueryOver<PanelaCorrida>()
    .Where(p => p.Id.IsIn(corridaPanelaIdList.Select(x => x[0]).ToArray()))
    .List<PanelaCorrida>();

But the problem is, i need only a few columns of each Table. With NHibernate i've tried with Projections, and with QueryOver, i've tried with SelectList, but each time they generate a error (could not found the property of ...) or they do not populate the entities in result.

How i could achieve this?

Note: This is my query in first place (in SQL):

select cd.num_panela_corrida, cd.num_panela, p.numero, l.num_local from scp_panela_corrida cd  
inner join scp_panela p on p.num_panela = cd.num_panela 
inner join scp_local l on l.num_local = cd.num_local and cd.num_panela_corrida
in (
    select 
        max( c.num_panela_corrida) as num_panela_corrida 
    from 
        scp_panela_corrida c 
    inner join
        scp_panela p on p.num_panela = c.num_panela
        and p.num_panela in (
            select 
                num_panela 
            from 
                scp_panela 
            where 
                idc_ativa = 1
        ) group by c.num_panela ) order by cd.num_panela_corrida desc

But the client don't want to use a Stored Procedure or HQL.

Any help is welcome.


Solution

  • Resolved with the following code (provided with the link of Radim Kohler).

    Radim, if you want, please answer this question with the provided link and i'll accept it as the answer. Thanks for your help.

    Panela panela = null;
    Local local = null;
    
    var query = session.QueryOver<PanelaCorrida>()
        .JoinAlias(c => c.Panela, () => panela)
        .Where (c => c.Id.IsIn(corridaPanelaIdList.ToArray()))
        .SelectList(list => list
        .Select(c => c.Id))
        .Select(c => c.CodCorrida)
        .Select(Projections.Property(() => panela.Id).As("Panela.Id"))
        .Select(Projections.Property(() => panela.IdcAtiva).As("Panela.IdcAtiva"))
        .TransformUsing(Transformers.AliasToBean(typeof(PanelaCorrida)));
    

    Don't know if is the best approach, but it worked. We will analyze best approaches using QueryOver/DetachedCriteria, but for now, this works great.

    Note: I've removed some columns, just to explain how it worked.

    Thanks again.