brunobritodev / AspNetCore.IQueryable.Extensions

LINQ extensions to help build IQueryAble Expressions
MIT License
159 stars 29 forks source link

Como utilizar SQL Join(Include) para Filtrar #16

Closed lpgoncalves closed 2 years ago

lpgoncalves commented 2 years ago

Por exemplo:


public Class Pedido
{
     public Guid CentroDistribuicaoId {get; set;}

     public virtual CentroDistribuicao {get; set;}
}

public Class CentroDistribuicao 
{
     public Guid Id {get; set;}

     public string Local {get; set;}
}

// Filtro manual
_pedidos.Include(pedido => pedido.CentroDistribuicao);

_pedidos.Where(pedido => pedido.CentroDistribuicao.Local == "SP");

Que seria uma query:

SELECT *  FROM Pedido
JOIN CentroDistribuicao ON CentroDistribuicao.Id = Pedido.CentroDistribuicaoId
WHERE CentroDistribuicao.Local = 'SP'

É possível utilizar essa extensão para buscar também com includes?

Caso seja possível, como isso seria feito?

GedanMagal commented 2 years ago

@lpgoncalves Cara, vê se isso te ajuda... Dentro da classe de filter, considerando que a property não seja um array, tenta utilizar dessa forma: image

brunobritodev commented 2 years ago

@lpgoncalves

Esse componente influencia na estrutura de arvore do IQueryable. Que é uma classe da System do .NET. O ORM que você utiliza, EF / NHibernate, são responsáveis por traduzir essa Arvore em Query pro SQL.

Nesse momento não temos componentes que auxiliem essa tradução ou influenciem o ORM diretamente. Até onde sei, não é possivel fazer esse Join.

O que acho que você pode tentar é adicionar os Includes e filtrar com o componente da forma como o @GedanMagal mencionou.

michelmicheloti commented 2 years ago

Olá pessoal... eu tinha criado uma issue antes de ver essa, perdão! A abordagem mencionado pelo @GedanMagal funciona!

No meu caso utilizo um ThenInclude e a solução que achei foi por um if nesse caso (Se alguém souber de uma abordagem melhor agradeço o compartilhamento)

Compartilho um cenario semelhante ao que apliquei a seguir

[Hi guys... I had created an issue before seeing this one, sorry! The approach mentioned by @GedanMagal works! In my case I use a ThenInclude and the solution I found was an if in this case (If anyone knows of a better approach I'd appreciate the sharing) I share a scenario similar to the one I applied below]

// Main Table
public class ReportEntity
{
    public int AreaId { get; set; }
    public AreaEntity Area { get; set; }
    public int CustomerId { get; set; }
    public CustomerEntity Customer { get; set; }

    public ICollection<ReportSerialNumberEntity> ReportSerialNumbers { get; set; }
}

public class AreaEntity
{
    public string Description { get; set; }
    public ICollection<ReportEntity> Reports { get; set; }
}

public class CustomerEntity
{
    public string Description { get; set; }
    public ICollection<ReportEntity> Reports { get; set; }
}

public class SerialNumberEntity
{
    public string Serial { get; set; }
    public ICollection<ReportSerialNumberEntity> ReportSerialNumbers { get; set; }
}

// Join Table -> Report x SerialNumber
public class ReportSerialNumberEntity
{
    public int ReportId { get; set; }
    public ReportEntity Report { get; set; }

    public int SerialNumberId { get; set; }
    public SerialNumberEntity SerialNumber { get; set; }
}

public class ReportQueryableDto : ICustomQueryable, IQueryPaging, IQuerySort
{
    [QueryOperator(Operator = WhereOperator.Contains, HasName = **"Area.Description"**)]
    public string Area { get; set; }

    [QueryOperator(Operator = WhereOperator.Contains, HasName = **"Customer.Description"**)]
    public string Customer { get; set; }

    public string SerialNumber { get; set; }

    public int? Limit { get; set; } = 10;
    public int? Offset { get; set; }
    public string Sort { get; set; }
}

public async Task<IEnumerable<ReportEntity>> SelectByQueryable(ReportQueryableDto queryableDto)
{
    IQueryable<ReportEntity> query =  _dataset.AsNoTracking()
                                                .Include(x => x.Area)
                                                .Include(x => x.Customer)
                                                .Include(x => x.ReportSerialNumbers)
                                                    .ThenInclude(y => y.SerialNumber)
                                                .AsQueryable();                            

    if(queryableDto.SerialNumber.IsPresent())
    {
        query = query.Where(x => x.ReportSerialNumbers.Any(y => y.SerialNumber.Serial.Equals(queryableDto.SerialNumber)));
    }

    return await query.Apply(queryableDto).ToListAsync();
}