Vra

Ons is besig met 'n Meld Viewer. Die gebruik sal die opsie om te filter deur die gebruiker, erns, ens In die Sql dae Ek sal aan die navraag string voeg nie, maar ek wil dit doen met Linq. Hoe kan ek voorwaardelik voeg waar-klousules?

Was dit nuttig?

Oplossing

As jy wil net filter indien sekere kriteria is verby, doen iets soos hierdie

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);

As jy dit doen op hierdie manier sal toelaat om jou Expression boom te wees presies wat jy wil. Op dié manier die SQL geskep sal presies wat jy nodig het en niks minder nie.

Ander wenke

As jy nodig het om te base filter op 'n Lys / Array gebruik die volgende:

    public List<Data> GetData(List<string> Numbers, List<string> Letters)
    {
        if (Numbers == null)
            Numbers = new List<string>();

        if (Letters == null)
            Letters = new List<string>();

        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();

    }

Ek het uiteindelik met behulp van 'n antwoord soortgelyk aan Daren se nie, maar met 'n IQueryable koppelvlak:

IQueryable<Log> 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();

Dit bou die navraag voordat slaan die databasis. Die opdrag sal nie hardloop totdat .ToList () aan die einde.

Wanneer dit kom by die voorwaardelike linQ, ek is baie lief vir die filters en pype patroon.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part- 3 /

Eintlik jy 'n uitbreiding metode vir elke filter geval dat neem in die IQueryable en 'n parameter te skep.

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

Nog 'n opsie sou wees om iets te gebruik soos die PredicateBuilder bespreek hier . Dit laat jou toe om kode soos die volgende te skryf:

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;

Let daarop dat ek net hierdie het om te werk met Linq 2 SQL. EntityFramework nie Expression.Invoke, wat nodig is vir hierdie metode om te werk nie implementeer. Ek het 'n vraag oor hierdie kwessie hier .

Deur dit te doen:

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

met hierdie in die where stelling:

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

beteken dat wanneer die finale navraag is geskep as lastNameSearch is false die navraag sal heeltemal enige SQL vir die laaste naam search weg te laat.

Ek opgelos hierdie met 'n uitbreiding metode toe te laat LINQ voorwaardelik tot aangesit wees in die middel van 'n vlot uitdrukking. Dit verwyder die behoefte om te breek die uitdrukking met if state.

.If() uitbreiding metode:

public static IQueryable<TSource> If<TSource>(
        this IQueryable<TSource> source,
        bool condition,
        Func<IQueryable<TSource>, IQueryable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

Dit laat jou toe om dit te doen:

return context.Logs
     .If(filterBySeverity, q => q.Where(p => p.Severity == severity))
     .If(filterByUser, q => q.Where(p => p.User == user))
     .ToList();

Hier is ook 'n IEnumerable<T> weergawe wat sal hanteer meeste ander LINQ uitdrukkings:

public static IEnumerable<TSource> If<TSource>(
    this IEnumerable<TSource> source,
    bool condition,
    Func<IEnumerable<TSource>, IEnumerable<TSource>> branch)
    {
        return condition ? source : branch(source);
    }

Dit is nie die mooiste ding, maar jy kan 'n lambda uitdrukking gebruik en slaag jou omstandighede opsioneel. In TSQL doen ek 'n groot deel van die volgende parameters maak opsionele:

  

Waar Veld = @FieldVar OR @FieldVar IS NULL

Jy kan dieselfde styl dupliseer met 'n die volgende lambda ( 'n voorbeeld van die beheer van verifikasie):

  

MyDataContext db = nuwe MyDataContext ();

     

leemte RunQuery (string PARAM1, string PARAM2, int? Param3) {

     
    

Func Check User = gebruiker =>

         
      

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

             

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

             

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

    
         

Gebruiker foundUser = db.Users.SingleOrDefault (Check User);

  
     

}

Ek het 'n soortgelyke vereiste onlangs en uiteindelik het gevind dat hierdie in hy MSDN. CSharp Monsters vir Visual Studio 2008

Die klasse ingesluit in die DynamicQuery monster van die aflaai toelaat om dinamiese navrae tydens looptyd skep in die volgende formaat:

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

Hierdie Gebruik jy 'n navraag string bou dinamiese tydens looptyd en slaag dit in die Waar () metode:

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

Net gebruik C # 's && operateur:

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

Edit: Ag, moet meer versigtig lees. Jy wou weet hoe om voorwaardelik voeg addisionele klousules. In daardie geval, ek het geen idee. :) Wat ek sou waarskynlik doen is net te berei verskeie navrae, en uit te voer die regte een, afhangende van wat ek beland nodig.

Jy kan 'n eksterne metode gebruik:

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

...

bool ConditionalCheck( typeofRec input ) {
    ...
}

Dit sal werk, maar kan nie afgebreek word in uitdrukking bome, wat beteken Linq om SQL sou die tjek kode hardloop teen elke rekord.

As alternatief:

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

Dit kan werk in uitdrukking bome, wat beteken dat Linq om SQL sou word new.

Wel, wat ek gedink het was jy kon die filter voorwaardes in 'n generiese lys van gezegdes sit:

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

    var predicates = new List<Predicate<string>>();

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

    var results = new List<string>();

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

Dit lei tot 'n lys met "my", "meyou", en "sny".

Jy kan optimaliseer dat deur dit te doen die foreach met die predicaten in 'n totaal ander funksie wat ORS al die predicaten.

Jy kan skep en gebruik hierdie uitbreiding metode

public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate)
{
    return isToExecute ? source.Where(predicate) : source;
}
Gelisensieer onder: CC-BY-SA met toeskrywing
Nie verbonde aan StackOverflow
scroll top