Kami sedang mengerjakan Log Viewer. Penggunaan akan memiliki opsi untuk memfilter berdasarkan pengguna, tingkat keparahan, dll. Pada hari Sql saya akan menambahkan ke string kueri, tetapi saya ingin melakukannya dengan Linq. Bagaimana cara menambahkan klausa where secara kondisional?
c#
linq
linq-to-sql
.net-3.5
sgwill
sumber
sumber
LINQ to Entities does not recognize the method 'System.String get_Item(System.String)' method, and this method cannot be translated into a store expression.
Jika Anda perlu memfilter berdasarkan List / Array, gunakan yang berikut ini:
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(); }
sumber
Saya akhirnya menggunakan jawaban yang mirip dengan Daren, tetapi dengan antarmuka IQuerable:
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();
Itu membangun kueri sebelum mencapai database. Perintah tidak akan berjalan hingga .ToList () di akhir.
sumber
Ketika berbicara tentang linq bersyarat, saya sangat menyukai pola filter dan pipa.
http://blog.wekeroad.com/mvc-storefront/mvcstore-part-3/
Pada dasarnya Anda membuat metode ekstensi untuk setiap kasus filter yang menggunakan IQuerable dan parameter.
public static IQueryable<Type> HasID(this IQueryable<Type> query, long? id) { return id.HasValue ? query.Where(o => i.ID.Equals(id.Value)) : query; }
sumber
Saya menyelesaikan ini dengan metode ekstensi untuk memungkinkan LINQ diaktifkan secara bersyarat di tengah ekspresi fasih. Ini menghilangkan kebutuhan untuk memecah ekspresi dengan
if
pernyataan..If()
metode ekstensi:public static IQueryable<TSource> If<TSource>( this IQueryable<TSource> source, bool condition, Func<IQueryable<TSource>, IQueryable<TSource>> branch) { return condition ? branch(source) : source; }
Ini memungkinkan Anda melakukan ini:
return context.Logs .If(filterBySeverity, q => q.Where(p => p.Severity == severity)) .If(filterByUser, q => q.Where(p => p.User == user)) .ToList();
Ini juga
IEnumerable<T>
versi yang akan menangani sebagian besar ekspresi LINQ lainnya:public static IEnumerable<TSource> If<TSource>( this IEnumerable<TSource> source, bool condition, Func<IEnumerable<TSource>, IEnumerable<TSource>> branch) { return condition ? branch(source) : source; }
sumber
Pilihan lain adalah menggunakan sesuatu seperti PredicateBuilder yang dibahas di sini . Ini memungkinkan Anda untuk menulis kode seperti berikut:
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;
Perhatikan bahwa saya hanya mendapatkan ini untuk bekerja dengan Linq 2 SQL. EntityFramework tidak mengimplementasikan Expression.Invoke, yang diperlukan agar metode ini berfungsi. Saya punya pertanyaan tentang masalah ini di sini .
sumber
Melakukan ini:
bool lastNameSearch = true/false; // depending if they want to search by last name,
memiliki ini dalam
where
pernyataan:where (lastNameSearch && name.LastNameSearch == "smith")
berarti bahwa ketika permintaan akhir dibuat, jika
lastNameSearch
adalahfalse
query-benar akan menghilangkan SQL apapun untuk pencarian nama terakhir.sumber
Ini bukan hal tercantik tetapi Anda dapat menggunakan ekspresi lambda dan meneruskan kondisi Anda secara opsional. Di TSQL saya melakukan banyak hal berikut untuk membuat parameter opsional:
Anda dapat menduplikasi gaya yang sama dengan lambda berikut (contoh pemeriksaan otentikasi):
sumber
Saya memiliki persyaratan serupa baru-baru ini dan akhirnya menemukan ini di MSDN dia. CSharp Sampel untuk Visual Studio 2008
Class yang disertakan dalam sampel DynamicQuery download memungkinkan Anda membuat kueri dinamis saat runtime dalam format berikut:
var query = db.Customers. Where("City = @0 and Orders.Count >= @1", "London", 10). OrderBy("CompanyName"). Select("new(CompanyName as Name, Phone)");
Dengan menggunakan ini, Anda bisa membuat string kueri secara dinamis saat runtime dan meneruskannya ke metode Where ():
string dynamicQueryString = "City = \"London\" and Order.Count >= 10"; var q = from c in db.Customers.Where(queryString, null) orderby c.CompanyName select c;
sumber
Anda dapat membuat dan menggunakan metode ekstensi ini
public static IQueryable<TSource> WhereIf<TSource>(this IQueryable<TSource> source, bool isToExecute, Expression<Func<TSource, bool>> predicate) { return isToExecute ? source.Where(predicate) : source; }
sumber
Cukup gunakan operator C # &&:
var items = dc.Users.Where(l => l.Date == DateTime.Today && l.Severity == "Critical")
Edit: Ah, perlu dibaca lebih teliti. Anda ingin tahu cara menambahkan klausa tambahan secara bersyarat . Kalau begitu, saya tidak tahu. :) Yang mungkin saya lakukan hanyalah menyiapkan beberapa kueri, dan menjalankan kueri yang benar, tergantung pada apa yang akhirnya saya perlukan.
sumber
Anda bisa menggunakan metode eksternal:
var results = from rec in GetSomeRecs() where ConditionalCheck(rec) select rec; ... bool ConditionalCheck( typeofRec input ) { ... }
Ini akan berhasil, tetapi tidak dapat dipecah menjadi pohon ekspresi, yang berarti Linq ke SQL akan menjalankan kode pemeriksaan terhadap setiap record.
Kalau tidak:
var results = from rec in GetSomeRecs() where (!filterBySeverity || rec.Severity == severity) && (!filterByUser|| rec.User == user) select rec;
Itu mungkin bekerja di pohon ekspresi, yang berarti Lini ke SQL akan dioptimalkan.
sumber
Nah, yang saya pikirkan adalah Anda bisa memasukkan kondisi filter ke dalam daftar Predikat umum:
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);
Itu menghasilkan daftar yang berisi "me", "meyou", dan "mow".
Anda dapat mengoptimalkannya dengan melakukan foreach dengan predikat dalam fungsi yang sangat berbeda dari OR semua predikat.
sumber