Linq: menambahkan kondisi ke klausa where secara kondisional

103

Saya punya pertanyaan seperti ini

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

Saya ingin menambahkan berbagai kondisi seperti usia, tinggi badan berdasarkan apakah ketentuan tersebut disediakan untuk metode yang menjalankan kueri ini. Semua kondisi akan mencakup Divisi pengguna. Jika usia diberikan, saya ingin menambahkannya ke kueri. Demikian pula, jika ketinggian disediakan, saya ingin menambahkannya juga.

Jika ini harus dilakukan dengan menggunakan kueri sql, saya akan menggunakan pembuat string untuk menambahkannya ke kueri strSQL utama. Tetapi di sini di Linq saya hanya dapat memikirkan menggunakan kondisi IF di mana saya akan menulis kueri yang sama tiga kali, dengan setiap blok IF memiliki kondisi tambahan. Apakah ada cara yang lebih baik untuk melakukan ini?

pengguna20358
sumber

Jawaban:

182

Jika Anda tidak memanggil ToList()dan pemetaan akhir Anda ke jenis DTO, Anda dapat menambahkan Whereklausa saat Anda pergi, dan membangun hasilnya di akhir:

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

Ini masih hanya akan menghasilkan satu panggilan ke database, yang akan seefisien menulis kueri dalam satu kali jalan.

Reed Copsey
sumber
1
Apakah saya perlu meletakkan semua kondisi where dalam pernyataan "var query = .."?
pengguna20358
4
Kondisi Di mana selanjutnya digabungkan sebagai ATAU atau sebagai DAN?
Vi100
4
@ vi100 mereka akan menjadi filter tambahan, jadi DAN
Reed Copsey
Syukurlah untuk kesederhanaan! Saya muak melihat 20+ baris pertanyaan Linq ketika yang di atas jauh lebih mudah dibaca
justanotherdev
Mengapa saya mendapatkan kesalahan iniLINQ 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

Saya biasanya menggunakan metode berantai tetapi memiliki masalah yang sama. Dan inilah ekstensi yang saya gunakan

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

Ini membantu untuk menghindari putusnya rantai. Juga sama ConditionalOrderBydan ConditionalOrderByDescendingsangat membantu.

Yuriy Granovskiy
sumber
Bermanfaat, tetapi tolong tambahkan contoh seperti apa tampilannya saat digunakan.
Suncat2000
1
Ini harus seperti: var fruits = await db.Fruits .ConditionalWhere (() => color! = Null, f => f.Color == color) .ConditionalWhere (() => matang! = Null, f => f .Ripe == matang) .ToListAsync ();
Yuriy Granovskiy
4
Bekerja dengan baik! Terima kasih! Saya juga membuat kelebihan beban untuk kondisi sebagai nilai boolean sederhana, bukan fungsi, untuk membuatnya lebih intuitif di mana delegasi akan menambahkan kerumitan yang tidak perlu. Saya cukup sering menggunakan metode ekstensi ini sekarang dan sangat menghargai solusi Anda.
Suncat2000
17

satu pilihan.

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

atau Anda dapat beralih ke sintaks metode untuk linq dan menggunakan kondisi if untuk melampirkan ekspresi ke klausa where.

Matthew Vines
sumber
3

Cukup saya menggunakannya di klausa where saya sebagai

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

Berdasarkan kondisi tertentu tambahkan kondisi dimana ...

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();
Melu
sumber
2

Ini kode saya untuk melakukan hal serupa. Ini adalah metode pada api Layanan Web WCF SOAP saya.

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

Kueri dasar Select(f => f)pada dasarnya berarti SEMUANYA, dan Whereklausa secara opsional dilampirkan padanya. Final Selectadalah opsional. Saya gunakan untuk mengubah objek baris database menjadi objek "Buah" hasil.

John Henckel
sumber
0

Dengan asumsi parameter berikut,

Int? Age = 18;

Cukup menggunakan &&dan ||operator bersyarat kita dapat memiliki versi lain.

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

Seperti Param1 Anda dapat menambahkan sejumlah parameter untuk kondisi pencarian.

Sushant Yelpale
sumber
0

Saya baru saja menemukan ini mencari sesuatu yang lain, tetapi saya pikir saya akan memasukkan versi lambda.

Pertama, saya akan membuat kelas seperti ini untuk meneruskan parameter ke lapisan data:

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

Kemudian, di lapisan data saya, sesuatu seperti ini:

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

Di mana Anda mewujudkan pertanyaan itu terserah Anda. Mungkin memiliki lapisan antara aplikasi dan data yang mengubah representasi khusus db menjadi db-agnostik (mungkin Anda meminta beberapa sumber data). Lapisan itu mungkin mendapatkan beberapa jenis queryable dari sumber ini dan memetakannya ke representasi POCO yang umum, misalnya.

Scott Peterson
sumber
Ups, saya tidak melihat jawaban John Henckel. Ide yang sama.
Scott Peterson
0

Hanya untuk menambahkan jawaban yang diterima di atas di sini , jika Anda melakukan pencarian dinamis pada gabungan, pertimbangkan untuk mengembalikan objek baru dengan kedua tabel (t1, t2) dalam kueri linq awal sehingga Anda dapat mengaksesnya secara individual untuk melakukan kondisional Cari.

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.

Saya mendapat jawaban yang saya cari di sini sehubungan dengan menggabungkan dua tabel dan menanyakan kolom tertentu di salah satu tabel

Riaan Saayman
sumber