FuncT, bool and ExpressionFuncT, bool

3

I'd like to know first what the difference between Func<T, bool> to Expression<Func<T, bool>>

And how do I convert from Func<T, bool> to Expression<Func<T, bool>> if it's possible.

Or else I need all my code to be Expression instead of Func. But I do not know how to convert and concatenate Expression. In the Filter () method.

public class MovimentoTratamento : Tratamento
{
    public string Nr_Nota_Fiscal { get; set; }
    public string Dt_Emissao_Nota_Fiscal { get; set; }
}

public abstract class Tratamento
{
    [Key]
    public int ID{ get; set; }
    public string Cd_Sap_Distribuidor_Matriz { get; set; }
    public string Cd_Sap_Distribuidor_Filial { get; set; }
    public DateTime Dt_Criacao { get; set; }
    public int Id_Log { get; set; }
}

private Func<Tratamento, bool> FiltroPadrao(FiltroViewModel filtroViewModel)
    {
        DateTime inicial, final;

        DateTime.TryParse(filtroViewModel.CargaInicial, out inicial);
        DateTime.TryParse(filtroViewModel.CargaFinal, out final);

        Func<Tratamento, bool> f = x =>
                                       ((final == DateTime.MinValue) || (x.Dt_Criacao >= inicial && x.Dt_Criacao <= final.AddDays(1)))
                                       &&
                                       (string.IsNullOrEmpty(filtroViewModel.CnpjMatriz) || x.Cd_Sap_Distribuidor_Matriz == filtroViewModel.CnpjMatriz)
                                       &&
                                       (string.IsNullOrEmpty(filtroViewModel.CnpjFilial) || x.Cd_Sap_Distribuidor_Filial == filtroViewModel.CnpjFilial)
                                       &&
                                       (filtroViewModel.TipoErro == "0" || x.Cd_Erro == filtroViewModel.TipoErro)
                                       &&
                                       (
                                            (filtroViewModel.StatusSelected == 3) ||
                                            (filtroViewModel.StatusSelected == 1 && x.Id_Log == 0) ||
                                            (filtroViewModel.StatusSelected == 2 && x.Id_Log > 0)
                                       );
        return f;
    }

    private Func<MovimentoTratamento, bool> FiltroNotaFiscal(FiltroViewModel filtroViewModel)
    {
        return x => (string.IsNullOrEmpty(filtroViewModel.NotaFiscal) || x.Nr_Nota_Fiscal == filtroViewModel.NotaFiscal);
    }

    public IQueryable<MovimentoTratamento> Filter()
    {
        Func<Tratamento, bool> filter = FiltroPadrao(vm);
        Func<MovimentoTratamento, bool> mov = FiltroNotaFiscal(vm);
        UnirExpressionMovimento(filter, mov);
        return repo.Get(f);
    }

    private Func<MovimentoTratamento, bool> UnirExpressionMovimento(Func<Tratamento, bool> filter, Func<MovimentoTratamento, bool> mov)
    {
        Func<MovimentoTratamento, bool> f = value => filter((Tratamento)value);

        return value => f(value) && mov(value);
    }
    
asked by anonymous 22.03.2016 / 12:15

1 answer

3

Original answer: Why would you use Expression > rather than Func?

Both do different things, while Func<T, bool> represents a code that will be executed, so much that the code will be converted to intermediate language and possibly executed.

The Expression<Func<T, bool>> contains a representation of what needs to be done, not necessarily the code that will be executed, for example, the following excerpt from a query using Entity Framework (TSQL):

context.Entities.Where((x) => x.Propriedade1 == x.Propriedade2);

In the above case, (x) => x.Propriedade1 == x.Propriedade2 will not be executed, but it contains information of what needs to be done, in which case it will be converted to a query SQL => SELECT * FROM Entities x WHERE x.Propriedade1 == x.Propriedade2

Note that the input and output of both may be the same, but the way they work, the compiled code and what they are intended for is completely different.

Now returning to the example above, if you want to reuse a Func<T, bool> to be used in Where (which expects a Expression<Func<T, bool>> ), you will have to encapsulate the function:

var funcao = new Func<Entity, bool>((x) => x.Propriedade1 == x.Propriedade2);
context.Entities.Where((x) => funcao(x));

Note that in this case, funcao(x) is not executed, but it contains the "instructions" that Expression needs, so it will understand what needs to be done.

Now I'd like to talk a bit about your implementation and what I disagree with it ... the first thing is about this variable repo , it looks like you're using some Repository Pattern implementation together with Entity Framework .

Instead of this, simply use Entity Framework , which in turn already implements Repository Pattern in a much more robust and complete way than you would be able to do it.

Second point, if you really want to isolate snippets of query usage so you can reuse them later, then make use of Extensions.

public class MovimentoTratamento : Tratamento
{
    public string Nr_Nota_Fiscal { get; set; }
    public string Dt_Emissao_Nota_Fiscal { get; set; }
}

public abstract class Tratamento
{
    [Key]
    public int ID{ get; set; }
    public string Cd_Sap_Distribuidor_Matriz { get; set; }
    public string Cd_Sap_Distribuidor_Filial { get; set; }
    public DateTime Dt_Criacao { get; set; }
    public int Id_Log { get; set; }
}

public static class TratamentoExtensions
{
    public static IQueryable<Tratamento> FiltroPadrao(this IQueryable<Tratamento> consulta, FiltroViewModel filtro)
    {
        DateTime inicial, final;
        DateTime.TryParse(filtro.CargaInicial, out inicial);
        DateTime.TryParse(filtro.CargaFinal, out final);

        return consulta.Where(x =>
            ((final == DateTime.MinValue) || (x.Dt_Criacao >= inicial && x.Dt_Criacao <= final.AddDays(1))) &&
            (string.IsNullOrEmpty(filtro.CnpjMatriz) || x.Cd_Sap_Distribuidor_Matriz == filtro.CnpjMatriz) &&
            (string.IsNullOrEmpty(filtro.CnpjFilial) || x.Cd_Sap_Distribuidor_Filial == filtro.CnpjFilial) &&
            (filtro.TipoErro == "0" || x.Cd_Erro == filtro.TipoErro) &&
            ((filtro.StatusSelected == 3) || (filtro.StatusSelected == 1 && x.Id_Log == 0) ||   (filtro.StatusSelected == 2 && x.Id_Log > 0));
    }

    private IQueryable<MovimentoTratamento> FiltroNotaFiscal(this IQueryable<MovimentoTratamento> consulta, FiltroViewModel filtro)
    {
        return consulta.Where(x => (string.IsNullOrEmpty(filtro.NotaFiscal) || x.Nr_Nota_Fiscal == filtro.NotaFiscal));
    }
}

public class TratamentoController
{
    public IQueryable<MovimentoTratamento> Filter(FiltroViewModel filtro)
    {
        using (var context = new MyDbContext())
        {
            return context.MovimentosTratamento.FiltroPadrao(filtro).FiltroNotaFiscal(filtro));
        }
    }
}

The reasons why I do not recommend using an additional Repository Pattern , you can see in the following link When to use Entity Framework with Repository Pattern?

I also recommend reading the following subject: Architecture of Stack Overflow and Stack Exchange

    
22.03.2016 / 12:47