Conexiuni Linq condiționate

Lucrăm la un Vizualizator de jurnal. Utilizarea va avea opțiunea de a filtra după utilizator, de severitate etc. În zilele de șase zile aș adăuga la șirul de interogare, dar vreau să o fac cu Linq. Cum pot adăuga în mod condițional unde-clauze?

0
fr hi bn

11 răspunsuri

dacă doriți să filtrați numai dacă sunt îndeplinite anumite criterii, faceți ceva de genul acesta

var logs = from log in context.Logs
           select log;

if (filterBySeverity)
    logs = logs.Where(p => p.Severity == severity);

if (filterByUser)
    logs = logs.Where(p => p.User == user);

Făcând astfel, acest mod vă va permite arborelui Expresie să fie exact ceea ce doriți. Astfel, SQL-ul creat va fi exact ceea ce aveți nevoie și nimic mai puțin.

0
adăugat
Da ... e cam greu de făcut. Cel mai bun lucru pe care l-am văzut este prin modelul specificării și trăgând predicatul în caietul de sarcini și apoi apelând specification.Or (someOtherSpecification). Practic, trebuie să vă scrieți propria arbore de expresie un pic. Exemplu de cod și explicație aici: codeinsanity.com/archive/2008/08/13/…
adăugat autor Darren Kopp, sursa
nu le filtrează în memorie. construiește o interogare și trimite toate condițiile din baza de date (cel puțin pentru majoritatea furnizorilor linq-to-x)
adăugat autor Darren Kopp, sursa
Bună Ai vreo sugestie pentru a face clauzele în cazul în care ORs în loc de ANDs ..?
adăugat autor Jon H, sursa
Am o întrebare stupidă: Dacă aceste jurnale sunt achiziționate din baza de date, primim toate jurnalele și apoi le filtrăm în memorie? Dacă da, atunci cum pot trece condițiile în baza de date
adăugat autor Ali Umair, sursa
această eroare LINQ către entități nu recunoaște metoda "System.String get_Item (System.String)" și această metodă nu poate fi tradusă într-o expresie a magazinului.
adăugat autor Ali Umair, sursa
@AliUmair Am avut erori similare. LINQ nu înțelege indexarea matricei. Trageți valoarea elementului matricei într-o variabilă locală și utilizați variabila în interogare. Exemplu: în loc de: var query = din x în context.Logs unde x.User == myArray [0] selectați log; utilizați: var u = myArray [0]; var query = de la x în context.Logs unde x.User == u selectați log;
adăugat autor Suncat2000, sursa

Am terminat folosind un răspuns similar cu cel al lui Daren, dar cu o interfață IQueryable:

IQueryable matches = m_Locator.Logs;

// Users filter
if (usersFilter)
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text);

//Severity filter
 if (severityFilter)
     matches = matches.Where(l => l.Severity == comboBoxSeverity.Text);

 Logs = (from log in matches
         orderby log.EventTime descending
         select log).ToList();

Aceasta construiește interogarea înainte de a atinge baza de date. Comanda nu va fi rulată până la terminarea funcției .Tolist ().

0
adăugat

Ei bine, ceea ce am crezut că ai putea pune condițiile de filtrare într-o listă generică de Predicate:

    var list = new List { "me", "you", "meyou", "mow" };

    var predicates = new List>();

    predicates.Add(i => i.Contains("me"));
    predicates.Add(i => i.EndsWith("w"));

    var results = new List();

    foreach (var p in predicates)
        results.AddRange(from i in list where p.Invoke(i) select i);               

Rezultă o listă care conține "eu", "meyou" și "mow".

Ați putea optimiza că făcând foreach cu predicatele într-o funcție complet diferită de ORs toate predicatele.

0
adăugat

Ați putea folosi o metodă externă:

var results =
    from rec in GetSomeRecs()
    where ConditionalCheck(rec)
    select rec;

...

bool ConditionalCheck( typeofRec input ) {
    ...
}

Acest lucru ar funcționa, dar nu poate fi împărțit în arbori de expresie, ceea ce înseamnă că Linq la SQL ar executa codul de verificare împotriva fiecărei înregistrări.

Alternativ:

var results =
    from rec in GetSomeRecs()
    where 
        (!filterBySeverity || rec.Severity == severity) &&
        (!filterByUser|| rec.User == user)
    select rec;

Acest lucru ar putea funcționa în arbori de expresie, ceea ce înseamnă Linq la SQL ar fi optimizat.

0
adăugat

O altă opțiune ar fi să utilizați ceva de genul PredicateBuilder discutat aici . Acesta vă permite să scrieți codul după cum urmează:

var newKids  = Product.ContainsInDescription ("BlackBerry", "iPhone");

var classics = Product.ContainsInDescription ("Nokia", "Ericsson")
                  .And (Product.IsSelling());

var query = from p in Data.Products.Where (newKids.Or (classics))
            select p;

Rețineți că am lucrat numai cu Linq 2 SQL. EntityFramework nu implementează Expression.Invoke, care este necesar pentru ca această metodă să funcționeze. Am o întrebare cu privire la această problemă aici .

0
adăugat
Aceasta este o metodă excelentă pentru cei care folosesc un Business Logic Layer în partea superioară a depozitului lor, împreună cu un instrument ca AutoMapper, pentru a face o hartă între obiectele de transfer de date și modelele Entity. Utilizarea constructorului de predicate vă va permite modificarea dinamică a IQueryable-ului înainte de al trimite în AutoMapper pentru aplatizare, adică aducerea listei în memorie. Rețineți că aceasta susține, de asemenea, Entity Framework.
adăugat autor chrisjsherm, sursa

When it comes to conditional linq, I am very fond of the filters and pipes pattern.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/

În principiu, creați o metodă de extensie pentru fiecare caz filtru care ia în considerare parametrul IQueryable și un parametru.

public static IQueryable HasID(this IQueryable query, long? id)
{
    return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query;
}
0
adăugat

Nu este cel mai frumos lucru, dar puteți folosi o expresie lambda și puteți trece condițiile opțional. În TSQL fac multe opțiuni pentru a face parametrii opțional:

Câmp WHERE = @FieldVar sau @FieldVar IS NULL

Puteți duplica același stil cu o lambda următoare (un exemplu de verificare a autentificării):

MyDataContext db = new MyDataContext();

void RunQuery(string param1, string param2, int? param3){

Func checkUser = user =>

((param1.Length > 0)? user.Param1 == param1 : 1 == 1) &&

((param2.Length > 0)? user.Param2 == param2 : 1 == 1) &&

((param3 != null)? user.Param3 == param3 : 1 == 1);

User foundUser = db.Users.SingleOrDefault(checkUser);

}

0
adăugat

I had a similar requirement recently and eventually found this in he MSDN. CSharp Samples for Visual Studio 2008

Clasele incluse în eșantionul DynamicQuery al descărcării vă permit să creați interogări dinamice în timpul rulării în următorul format:

var query =
db.Customers.
Where("City = @0 and Orders.Count >= @1", "London", 10).
OrderBy("CompanyName").
Select("new(CompanyName as Name, Phone)");

Folosind acest lucru, puteți construi un șir de interogări dinamic la timpul de execuție și îl puteți transfera în metoda Where ():

string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; 
var q = from c in db.Customers.Where(queryString, null)
        orderby c.CompanyName
        select c;
0
adăugat

Just use C#'s && operator:

var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")

Editați: Ah, trebuie să citiți mai atent. Ați vrut să știți cum să condiționați adăugați clauze suplimentare. În acest caz, nu am idee. :) Ceea ce aș face, probabil, este să pregătesc câteva întrebări și să execut una potrivită, în funcție de ceea ce am avut nevoie.

0
adăugat

Dacă aveți nevoie să filtrați baza pe o Listă/Array utilizați următoarele:

    public List GetData(List Numbers, List Letters)
    {
        if (Numbers == null)
            Numbers = new List();

        if (Letters == null)
            Letters = new List();

        var q = from d in database.table
                where (Numbers.Count == 0 || Numbers.Contains(d.Number))
                where (Letters.Count == 0 || Letters.Contains(d.Letter))
                select new Data
                {
                    Number = d.Number,
                    Letter = d.Letter,
                };
        return q.ToList();

    }
0
adăugat
Acesta este de departe cel mai bun și cel mai corect răspuns. Condiționată || compară doar prima parte și ignoră a doua, dacă prima parte este adevărată ... bine făcut!
adăugat autor Serj Sagan, sursa
Acest construct include partea 'sau' a expresiei din interogarea SQL generată. Răspunsul acceptat va genera declarații mai eficiente. În funcție de optimizările furnizorului de date, desigur. LINQ-to-SQL poate avea o optimizare mai bună, dar LINQ-to-Entities nu.
adăugat autor Suncat2000, sursa

Făcând acest lucru:

bool lastNameSearch = true/false;//depending if they want to search by last name,

având în codul unde :

where (lastNameSearch && name.LastNameSearch == "smith")

înseamnă că atunci când interogarea finală este creată, dacă lastNameSearch este false interogarea va omite complet orice SQL pentru căutarea ultimului nume.

0
adăugat
Depinde de furnizorul de date. LINQ-to-Entities nu o optimizează atât de bine.
adăugat autor Suncat2000, sursa