Linq: where cümlesine koşullu olarak koşullar ekleme


106

Bunun gibi bir sorgum var

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

Bu sorguyu çalıştıran yönteme bu koşulların sağlanıp sağlanmadığına bağlı olarak yaş, boy gibi çeşitli koşulları eklemek istiyorum. Tüm koşullar, kullanıcı Bölümünü içerecektir. Yaş belirtilmişse, bunu sorguya eklemek istiyorum. Benzer şekilde, eğer yükseklik sağlanmışsa, bunu da eklemek istiyorum.

Bu, sql sorguları kullanılarak yapılacak olsaydı, ana strSQL sorgusuna eklenmeleri için dize oluşturucuyu kullanırdım. Ama burada Linq'te, her bir IF bloğunun ek bir koşulu ile aynı sorguyu üç kez yazacağım bir IF koşulunu kullanmayı düşünebilirim. Bunu yapmanın daha iyi bir yolu var mı?

Yanıtlar:


186

Eğer çağırmazsanız ToList()ve DTO türüne son eşlemeniz varsa, ilerlerken Wherecümle ekleyebilir ve sonuçları sonunda oluşturabilirsiniz:

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

Bu yine de veritabanına yalnızca tek bir çağrı ile sonuçlanacaktır ve bu, sorguyu tek geçişte yazmak kadar etkili olacaktır.


1
"Var query = .." ifadesine tüm where koşullarını koymam gerekir mi?
user20358

4
Sonraki Nerede koşullar OR olarak mı yoksa VE olarak mı toplanır?
Vi100

4
@ vi100 bunlar ek filtreler olacak, yani VE
Reed Copsey

Sadelik için çok şükür! Yukarıdakiler çok daha okunaklı olduğunda 20+ satır Linq sorgularını görmekten bıktım
justanotherdev

Neden bu hatayı alıyorumLINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Ali Umair

19

Genellikle yöntem zincirleme kullanıyorum ama aynı problemi yaşıyorum. Ve işte kullandığım uzantı

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

Zincir kırılmalarını önlemeye yardımcı olur. Ayrıca aynı ConditionalOrderByve ConditionalOrderByDescendingfaydalıdır.


Yararlı, ancak kullanımda nasıl görüneceğine dair bir örnek ekler misiniz lütfen?
Suncat2000

1
Şöyle olmalıdır: var meyveler = await db.Fruits .ConditionalWhere (() => color! = Null, f => f.Color == color) .ConditionalWhere (() => olgun! = Null, f => f .Ripe == olgun) .ToListAsync ();
Yuriy Granovskiy

4
Harika çalışıyor! Teşekkürler! Ayrıca, bir temsilcinin gereksiz karmaşıklık ekleyeceği durumlarda durumu daha sezgisel hale getirmek için, işlev yerine basit bir boole değeri olarak koşul için bir aşırı yük yaptım . Bu uzatma yöntemini şu anda oldukça sık kullanıyorum ve çözümünüzü çok takdir ediyorum.
Suncat2000

18

bir seçenek.

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

veya linq için yöntem sözdizimine geçebilir ve where cümlesine ifadeler eklemek için if koşullarını kullanabilirsiniz.


4

Basitçe, nerede cümlesimde kullanıyorum

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

3

Belirli koşullara bağlı olarak, nerede koşulunu ekleyin ...

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

2

İşte benzer bir şey yapmak için kodum. Bu, WCF SOAP Web Hizmeti API'mdeki bir yöntemdir.

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

Temel sorgu, Select(f => f)temelde HER ŞEY anlamına gelir ve Wheretümceler isteğe bağlı olarak ona eklenir. Final Selectisteğe bağlıdır. Veritabanı satır nesnelerini sonuç "Meyve" nesnelerine dönüştürmek için kullanıyorum.


0

Aşağıdaki parametreyi varsayarsak,

Int? Age = 18;

Basitçe &&ve ||koşullu operatörleri kullanarak başka bir versiyona sahip olabiliriz.

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

Param1 gibi, arama koşulu için istediğiniz sayıda parametre ekleyebilirsiniz.


0

Buna başka bir şey ararken rastladım, ancak lambda versiyonunu atayım dedim.

İlk olarak, parametreleri bir veri katmanına geçirmek için bunun gibi bir sınıf oluşturardım:

   public class SearchParameters() {
       public int? Age {get; set;}
       public string Division {get;set;}
       etc
    }

Ardından, veri katmanımda şuna benzer bir şey:

public IQueryable<User> SearchUsers(SearchParameters params) 
{
    var query = Context.Users;
    if (params.Age.HasValue)
    {
         query = query.Where(u => u.Age == params.Age.Value);
    }
    if (!string.IsNullOrEmpty(params.Division)
    {
        query = query.Where(u => u.Division == params.Division);
    }
    etc
    return query;
}

Sorguyu nerede gerçekleştireceğiniz size kalmış. Uygulama ile veriler arasında, db'ye özgü gösterimleri db-agnostiğe dönüştüren bir katman olabilir (belki birden çok veri kaynağını sorguluyorsunuz). Bu katman, bu kaynaklardan birden çok türde sorgulanabilir öğe alabilir ve bunları örneğin ortak bir POCO temsiliyle eşleştirebilir.


Oops, John Henckel'in cevabını görmedim. Aynı fikir.
Scott Peterson

0

Yukarıdaki kabul cevaba eklemek burada size koşullu yapmak bunları tek tek erişebilmek için bir katılmak üzerinde dinamik bir arama yapıyorsanız, ilk linq sorguda iki tablodan (t1, t2) ile yeni bir nesne döndürmek için dikkate arama.

var query = from t1 in _context.Table1
            join t2 in _context.Table2 on t1.Table1Id equals t2.Table1IdId
            select new { t1, t2 };

        if (!string.IsNullOrEmpty(searchProperty1))
        {
            query = query.Where(collection => collection.t1.TableColumn == searchProperty1);
        }
        if (!string.IsNullOrEmpty(searchProperty2))
        {
            query = query.Where(collection => collection.t2.TableColumn == searchProperty2);
        }
        ....etc.

Burada aradığım cevabı iki tabloyu birleştirme ve tablodan herhangi birindeki belirli sütunları sorgulama konusunda aldım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.