2017-05-19 1 views
3

Wenn MesAno ist "" //string.EmptyWarum funktioniert diese optionale Parameter LINQ WHERE nicht?

 DateTime dateAux; 
     int ano = 0; 
     int mes = 0; 
     if (MesAno.Trim() != "" && DateTime.TryParse("01/" + MesAno, out dateAux)) 
     { 
      ano = dateAux.Year; 
      mes = dateAux.Month; 
     } 


       lista = session.Query<Evidencias>().Timeout(30) 
        .Where(m => m.Produto.Distribuidora.Id == myUser.Terceiro.Distribuidora.Id) 
        //.Where(m => MesAno != "" ? (m.DataInclusao.Year == ano && m.DataInclusao.Month == mes) : true) 
        .Where(m => Produto != "" ? m.Produto.CodigoProduto.Contains(Produto) : true) 
        .Where(m => Titular != "" ? m.NomeTitular.Contains(Titular) : true) 
        .Where(m => Instalacao != "" ? m.CodigoInstalacao.Contains(Instalacao) : true) 
        .Where(m => ano != 0 ? m.DataInclusao.Year == ano : true) 
        .Where(m => mes != 0 ? m.DataInclusao.Month == mes : true) 
        .OrderByDescending(m => m.DataInclusao).Take(3000).ToList(); 

Dann wird die generierte SQL-WHERE ist:

where [email protected] and @P3=1 and @P4=1 and @P5=1 and datepart(year, evidencias0_.DataInclusao)[email protected] and datepart(month, evidencias0_.DataInclusao)[email protected] order by evidencias0_.DataInclusao desc',N'@P1 int,@P2 int,@P3 bit,@P4 bit,@P5 bit,@P6 int,@P7 int',3000,1,1,1,1,0,0 

Der Fremde Teil ist:

datepart(year, evidencias0_.DataInclusao)[email protected] and datepart(month, evidencias0_.DataInclusao)[email protected] 

Warum nicht diese:

@P6=1 and @P7=1 

Antwort

4

Es ist natürlich seltsam, aber niemand ist perfekt - die Übersetzung von LINQ-Ausdrucksbaum nach SQL ist ein ziemlich kompliziertes Thema, muss viele Dinge berücksichtigen und kann daher einige "offensichtliche" Dinge für Menschen vermissen. Die Übersetzung ist also nicht immer perfekt, aber sobald sie keine Ausnahmen erzeugt und das richtige Ergebnis liefert, sollte sie akzeptabel sein.

Jedoch Sie bequem die Übersetzern helfen können redundante Parameter und Bedingungen (zumindest für Top-Level-IQueryable<T> wie Ihre) durch eine benutzerdefinierten bedingte Where Erweiterung Methode wie folgt zu schreiben zu vermeiden:

public static class QueryableExtensions 
{ 
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, bool condition, Expression<Func<T, bool>> predicate) 
    { 
     return condition ? source.Where(predicate) : source; 
    } 
} 

so könnten Sie verwenden:

lista = session.Query<Evidencias>().Timeout(30) 
     .Where(m => m.Produto.Distribuidora.Id == myUser.Terceiro.Distribuidora.Id) 
     .WhereIf(Produto != "", m => m.Produto.CodigoProduto.Contains(Produto)) 
     .WhereIf(Titular != "", m => m.NomeTitular.Contains(Titular)) 
     .WhereIf(Instalacao != "", m => m.CodigoInstalacao.Contains(Instalacao)) 
     .WhereIf(ano != 0, m => m.DataInclusao.Year == ano) 
     .WhereIf(mes != 0, m => m.DataInclusao.Month == mes) 
     .OrderByDescending(m => m.DataInclusao).Take(3000).ToList(); 

und die erzeugte SQL wird nicht @ P4, P5 @, @ P6, P7 @ Parameter und seltsame Bedingungen.

+0

ehrfürchtige Antwort. einfach, einfach, schnell und perfekt. Was ist der beste Weg, um diese Klasse in mein Projekt zu bringen? Eine Datei nach Erweiterungsklasse in einem Paket? Oder eine LinqExtension-Klassendatei mit dieser einen Klasse und anderen Erweiterungen Linq-Klasse ??? – MarcioAT

+0

Gern geschehen, froh, dass es geholfen hat :) In Bezug auf die Frage, es ist eine Frage der persönlichen Vorlieben/Stil. Ich habe normalerweise eine Klasse (Datei) wie diese mit vielen eigenen Erweiterungen und schließe sie (Kopie) in jedes Projekt ein, das ich brauche. Auch hier liegt es an Ihnen - verwenden Sie, was auch immer in Ihren aktuellen Programmierpraktiken passt :) –