2012-06-04 13 views
60

Mam zapytanie jak toLINQ: dodawanie warunków klauzuli gdzie warunkowo

(from u in DataContext.Users 
     where u.Division == strUserDiv 
     && u.Age > 18 
     && u.Height > strHeightinFeet 
     select new DTO_UserMaster 
     { 
     Prop1 = u.Name, 
     }).ToList(); 

chcę dodać różne warunki jak wiek, wzrost podstawie tego, czy warunki te zostały dostarczone do sposobu uruchomiony tej kwerendy. Wszystkie warunki będą obejmować podział użytkownika. Jeśli podano wiek, chcę dodać to do zapytania. Podobnie, gdyby wysokość była przewidziana, chcę to również dodać.

Gdyby to miało być zrobione przy użyciu zapytań sql, użyłbym konstruktora łańcuchów do dołączenia ich do głównej kwerendy strSQL. Ale tutaj w Linq mogę myśleć tylko o korzystaniu z warunku IF, w którym napiszę to samo zapytanie trzykrotnie, przy czym każdy blok IF ma dodatkowy warunek. Czy jest lepszy sposób to zrobić?

Dziękujemy za poświęcony czas ..

+0

Piękne pytanie! z dobrze sformułowanym nagłówkiem, z piękniejszą odpowiedzią! – Irfan

Odpowiedz

108

Jeśli nie zadzwonić ToList() a ostateczna mapowanie do typu DTO można dodać Where klauzule jak iść i budować wyniki na koniec:

var query = from u in DataContext.Users 
    where u.Division == strUserDiv 
    && u.Age > 18 
    && u.Height > strHeightinFeet 
    select u; 

if (useAge) 
    query = query.Where(u => u.Age > age); 

if (useHeight) 
    query = query.Where(u => u.Height > strHeightinFeet); 

// Build the results at the end 
var results = query.Select(u => new DTO_UserMaster 
    { 
    Prop1 = u.Name, 
    }).ToList(); 

ten będzie nadal prowadzić tylko w pojedyncze wywołanie do bazy danych, które będzie skutecznie równie skuteczne, jak pisanie zapytania w jednym przebiegu.

+0

Czy muszę umieścić wszystkie warunki where w instrukcji "var query = .."? – user20358

+1

@ user20358 Nie - sposób, w jaki napisano powyżej, działa dobrze. –

+2

Kolejne sytuacje, w których warunki są agregowane jako LUB lub ORAZ? – Vi100

12

Jedna opcja.

bool? age = null 

(from u in DataContext.Users 
      where u.Division == strUserDiv 
      && (age == null || (age != null && u.Age > age.Value)) 
      && u.Height > strHeightinFeet 
      select new DTO_UserMaster 
      { 
      Prop1 = u.Name, 
      }).ToList(); 

lub można przełączyć się na składnię metody dla linq i użyć, jeśli warunki dołączyć załączenia do klauzuli where.

+0

Nie mogę uwierzyć, że o tym nie myślałem. – phil

2

Oto mój kod, aby zrobić coś podobnego. Jest to metoda w moim interfejsie API usług WWW SOF WCF.

public FruitListResponse GetFruits(string color, bool? ripe) 
    { 
     try 
     { 
      FruitContext db = new FruitContext(); 
      var query = db.Fruits.Select(f => f); 
      if (color != null) 
      { 
       query = query.Where(f => f.Color == color); 
      } 
      if (ripe != null) 
      { 
       query = query.Where(f => f.Ripe == ripe); 
      } 
      return new FruitListResponse 
      { 
       Result = query.Select(f => new Fruit { Id = f.FruitId, Name = f.Name }).ToList() 
      }; 
     } 
     catch (Exception e) 
     { 
      return new FruitListResponse { ErrorMessage = e.Message }; 
     } 
    } 

Zapytanie podstawa jest Select(f => f) co oznacza w zasadzie wszystko i klauzule Where są ewentualnie przyłączone do niego. Ostateczny Select jest opcjonalny. Używam do konwertowania obiektów wierszy bazy danych na obiekty wynikowe "Owoc".

+1

ładne wyjaśnienie – xDJR1875

7

Zazwyczaj używam metody łańcuchowej, ale mam ten sam problem. I tutaj jest rozszerzenie używam

public static IQueryable<T> ConditionalWhere<T>(
     this IQueryable<T> source, 
     Func<bool> condition, 
     Expression<Func<T, bool>> predicate) 
    { 
     if (condition()) 
     { 
      return source.Where(predicate); 
     } 

     return source; 
    } 

Pomaga uniknąć pęknięć łańcucha. Pomocne są również te same ConditionalOrderBy i ConditionalOrderByDescending.

+0

Pomocne, ale czy mógłbyś dodać przykład tego, jak będzie wyglądać w użyciu. – Suncat2000

+1

Powinno być takie: var fruits = czekaj db.Fruits .ConditionalWhere (() => color! = Null, f => f.Color == color) .ConditionalWhere (() => dojrzałe! = Zero, f => f.Ripe == ripe) .ToListAsync(); –

+1

Działa świetnie! Dzięki! Zrobiłem też przeciążenie dla * warunku * jako prostej wartości boolowskiej zamiast funkcji, aby uczynić ją bardziej intuicyjną, gdy delegat dodawałby niepotrzebnej złożoności. Bardzo często używam tej metody rozszerzenia i bardzo doceniam twoje rozwiązanie. – Suncat2000

2

prostu używam go w moim klauzuli WHERE jako

public IList<ent_para> getList(ent_para para){ 
    db.table1.Where(w=>(para.abc!=""?w.para==para.abc:true==true) && (para.xyz!=""?w.xyz==para.xyz:true==true)).ToList(); 
} 
0

podstawie pewnej condtion dodać warunek WHERE ...

from u in DataContext.Users 
where u.Division == strUserDiv 
&& u.Age != null ? u.Age > 18 : 1== 1 
&& u.Height != null ? u.Height > 18 : 1== 1 
&& u.Height != null ? u.Height > 18 : 1== 1 
select new DTO_UserMaster 
     { 
     Prop1 = u.Name, 
     }).ToList();