2009-03-30 11 views
5

Załóżmy, że mam tablicę i chcę wykonać kwerendę LINQ przeciwko varcharowi, który zwraca wszystkie rekordy, które mają element tablicy w dowolnym miejscu w varcharze.LINQ dla LIKE kwerend elementów tablicy

Coś takiego byłoby słodkie.

string[] industries = { "airline", "railroad" }

var query = from c in contacts where c.industry.LikeAnyElement(industries) select c

Jakieś pomysły?

+0

LINQ do SQL, LINQ do elementów, LINQ do obiektów? – Lucas

Odpowiedz

5

To jest rzeczywiście przykładem używam w moim „Express Yourself” prezentacji na czymś, co jest trudne do zrobienia w regularnych LINQ; O ile mi wiadomo, najłatwiej to zrobić, pisząc predykat ręcznie. Używam przykład poniżej (należy pamiętać, że to działa jednakowo dla StartsWith etc):

using (var ctx = new NorthwindDataContext()) 
    { 
     ctx.Log = Console.Out; 
     var data = ctx.Customers.WhereTrueForAny(
      s => cust => cust.CompanyName.Contains(s), 
      "a", "de", "s").ToArray(); 
    } 
// ... 
public static class QueryableExt 
{ 
    public static IQueryable<TSource> WhereTrueForAny<TSource, TValue>(
     this IQueryable<TSource> source, 
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     return source.Where(BuildTrueForAny(selector, values)); 
    } 
    public static Expression<Func<TSource, bool>> BuildTrueForAny<TSource, TValue>(
     Func<TValue, Expression<Func<TSource, bool>>> selector, 
     params TValue[] values) 
    { 
     if (selector == null) throw new ArgumentNullException("selector"); 
     if (values == null) throw new ArgumentNullException("values"); 
     if (values.Length == 0) return x => true; 
     if (values.Length == 1) return selector(values[0]); 

     var param = Expression.Parameter(typeof(TSource), "x"); 
     Expression body = Expression.Invoke(selector(values[0]), param); 
     for (int i = 1; i < values.Length; i++) 
     { 
      body = Expression.OrElse(body, 
       Expression.Invoke(selector(values[i]), param)); 
     } 
     return Expression.Lambda<Func<TSource, bool>>(body, param); 
    } 

} 
+0

Nice! (Proszę wpisać na co najmniej 10 znaków.) – Lucas

4
from c in contracts 
where industries.Any(i => i == c.industry) 
select c; 

coś w tym stylu. użyj dowolnej metody z kolekcji.

+1

Powoduje to wyjątek w LINQ do SQL. Może być napisany jako "where industries.Contains (c.industry)", co tłumaczy się jako "c.industry IN (" airline "," railroad ")", ale chce porównania LIKE. – Lucas

0

Niestety, podobnie jak nie jest obsługiwana w LINQ to SQL, jak na tutaj:

http://msdn.microsoft.com/en-us/library/bb882677.aspx

Aby obejść ten problem, trzeba będzie napisać procedurę przechowywaną, która będzie akceptować parametry, których chcesz używać w podobne instrukcje, a następnie wywołanie tego z LINQ do SQL.


Należy zauważyć, że kilka odpowiedzi sugeruje użycie Contains. To nie zadziała, ponieważ wygląda na to, że cały ciąg pasuje do elementu tablicy. Co jest szukali jest element tablicy mają być zawarte w samej dziedzinie, coś jak:

industry LIKE '%<element>%' 

jako Clark wspomniał w komentarzu, można użyć połączenia do IndexOf na każdym elemencie (co powinno przełożyć do wywołania SQL):

string[] industries = { "airline", "railroad" } 

var query = 
    from c in contacts 
    where 
     c.industry.IndexOf(industries[0]) != -1 || 
     c.industry.IndexOf(industries[1]) != -1 

Jeśli znasz długość tablicy i liczbę elementów, możesz ją zakodować. Jeśli tego nie zrobisz, będziesz musiał utworzyć instancję Expression na podstawie tablicy i pola, na które patrzysz.

+0

Wiedziałem, że .. moje złe .. charindex! = -1 dla każdego elementu w tablicy byłoby dobrze. – Clark

+1

faktycznie LIKE jest nieco obsługiwane w LINQ do SQL. "gdzie c.industry.Contains (" airline ")" działa i tłumaczy się na "WHERE c.industry LIKE"% airline%. "Ale chce LIKE któregokolwiek z podanych wartości, nie tylko jednego. – Lucas

3

IEnumerable.Contains() przekłada się na SQL IN jak w:

WHERE 'american airlines' IN ('airline', 'railroad') -- FALSE 

String.Contains() co przekłada się na SQL LIKE% ...% jak w:

WHERE 'american airlines' LIKE '%airline%' -- TRUE 

Jeśli chcesz styki gdzie przemysł kontaktu jest LIKE (zawiera) dowolną z branż, chcesz połączyć zarówno Any(), jak i String.Contains() w coś takiego:

string[] industries = { "airline", "railroad" }; 

var query = from c in contacts 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 

Jednakże połączenie zarówno jakąkolwiek() i String.Contains(), jak to jest nie obsługiwane LINQ SQL. Jeśli zestaw danych branżach jest niewielki, można spróbować coś takiego:

where c.Industry.Contains("airline") || 
     c.Industry.Contains("railroad") || ... 

lub (chociaż zwykle nie zalecane), czy zestaw styków jest na tyle mała, można przynieść je wszystkie z DB i zastosować filtr z LINQ do Objects za pomocą contacts.AsEnumerable() lub kontaktów.ToList() jako źródła zapytania powyżej:

var query = from c in contacts.AsEnumerable() 
      where industries.Any(i => c.Industry.Contains(i)) 
      select c; 
1

to będzie działać, jeśli zbudować kwerendę w następujący sposób:

var query = od cw contacts.AsEnumerable() wybierz c;

zapytanie = zapytanie. Gdzie (c => (c.Industry.Contains ("linia lotnicza")) || (c.Industry.Contains ("railroad")));

wystarczy programowo wygenerować powyższy ciąg, jeśli parametry linii lotniczych i kolejowych są danymi wejściowymi użytkownika. To było w rzeczywistości trochę bardziej skomplikowane, niż się spodziewałem. Zobacz artykuł - http://www.albahari.com/nutshell/predicatebuilder.aspx