Saya mencoba membuat kueri yang menggunakan daftar id di klausa where, menggunakan api klien Silverlight ADO.Net Data Services (dan karenanya Linq To Entities). Adakah yang tahu tentang solusi untuk Mengandung tidak didukung?
Saya ingin melakukan sesuatu seperti ini:
List<long?> txnIds = new List<long?>();
// Fill list
var q = from t in svc.OpenTransaction
where txnIds.Contains(t.OpenTransactionId)
select t;
Mencoba ini:
var q = from t in svc.OpenTransaction
where txnIds.Any<long>(tt => tt == t.OpenTransactionId)
select t;
Tapi mendapat "Metode 'Any' tidak didukung".
c#
linq
entity-framework
.net-3.5
linq-to-entities
James Bloomer
sumber
sumber
Jawaban:
Pembaruan: EF ≥ 4 mendukung
Contains
secara langsung (CheckoutAny
), jadi Anda tidak memerlukan solusi apa pun.public static IQueryable<TEntity> WhereIn<TEntity, TValue> ( this ObjectQuery<TEntity> query, Expression<Func<TEntity, TValue>> selector, IEnumerable<TValue> collection ) { if (selector == null) throw new ArgumentNullException("selector"); if (collection == null) throw new ArgumentNullException("collection"); if (!collection.Any()) return query.Where(t => false); ParameterExpression p = selector.Parameters.Single(); IEnumerable<Expression> equals = collection.Select(value => (Expression)Expression.Equal(selector.Body, Expression.Constant(value, typeof(TValue)))); Expression body = equals.Aggregate((accumulate, equal) => Expression.Or(accumulate, equal)); return query.Where(Expression.Lambda<Func<TEntity, bool>>(body, p)); } //Optional - to allow static collection: public static IQueryable<TEntity> WhereIn<TEntity, TValue> ( this ObjectQuery<TEntity> query, Expression<Func<TEntity, TValue>> selector, params TValue[] collection ) { return WhereIn(query, selector, (IEnumerable<TValue>)collection); }
PEMAKAIAN:
public static void Main() { using (MyObjectContext context = new MyObjectContext()) { //Using method 1 - collection provided as collection var contacts1 = context.Contacts.WhereIn(c => c.Name, GetContactNames()); //Using method 2 - collection provided statically var contacts2 = context.Contacts.WhereIn(c => c.Name, "Contact1", "Contact2", "Contact3", "Contact4" ); } }
sumber
if (!collection.Any()) //action;
, ganti tindakan - ganti dengan hanya mengembalikan kueri kosong dari jenis yang diminta untuk kinerja terbaik - atau hapus saja baris ini.Anda dapat kembali ke tangan coding beberapa e-sql (perhatikan kata kunci "it"):
return CurrentDataSource.Product.Where("it.ID IN {4,5,6}");
Berikut adalah kode yang saya gunakan untuk menghasilkan beberapa e-sql dari koleksi, YMMV:
string[] ids = orders.Select(x=>x.ProductID.ToString()).ToArray(); return CurrentDataSource.Products.Where("it.ID IN {" + string.Join(",", ids) + "}");
sumber
Dari MSDN :
static Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>( Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values) { if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); } if (null == values) { throw new ArgumentNullException("values"); } ParameterExpression p = valueSelector.Parameters.Single(); // p => valueSelector(p) == values[0] || valueSelector(p) == ... if (!values.Any()) { return e => false; } var equals = values.Select( value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue)))); var body = equals.Aggregate<Expression>((accumulate, equal) => Expression.Or(accumulate, equal)); return Expression.Lambda<Func<TElement, bool>>(body, p); }
dan kueri menjadi:
var query2 = context.Entities.Where(BuildContainsExpression<Entity, int>(e => e.ID, ids));
sumber
Saya tidak yakin tentang Silverligth, tetapi di linq ke objek saya selalu menggunakan any () untuk kueri ini.
var q = from t in svc.OpenTranaction where txnIds.Any(t.OpenTransactionId) select t;
sumber
Untuk melengkapi rekaman, inilah kode yang akhirnya saya gunakan (pengecekan kesalahan dihilangkan untuk kejelasan) ...
// How the function is called var q = (from t in svc.OpenTransaction.Expand("Currency,LineItem") select t) .Where(BuildContainsExpression<OpenTransaction, long>(tt => tt.OpenTransactionId, txnIds)); // The function to build the contains expression static System.Linq.Expressions.Expression<Func<TElement, bool>> BuildContainsExpression<TElement, TValue>( System.Linq.Expressions.Expression<Func<TElement, TValue>> valueSelector, IEnumerable<TValue> values) { if (null == valueSelector) { throw new ArgumentNullException("valueSelector"); } if (null == values) { throw new ArgumentNullException("values"); } System.Linq.Expressions.ParameterExpression p = valueSelector.Parameters.Single(); // p => valueSelector(p) == values[0] || valueSelector(p) == ... if (!values.Any()) { return e => false; } var equals = values.Select(value => (System.Linq.Expressions.Expression)System.Linq.Expressions.Expression.Equal(valueSelector.Body, System.Linq.Expressions.Expression.Constant(value, typeof(TValue)))); var body = equals.Aggregate<System.Linq.Expressions.Expression>((accumulate, equal) => System.Linq.Expressions.Expression.Or(accumulate, equal)); return System.Linq.Expressions.Expression.Lambda<Func<TElement, bool>>(body, p); }
sumber
Berikut adalah contoh tempat saya mendemonstrasikan cara menulis kueri berbasis set menggunakan DataServiceContext: http://blogs.msdn.com/phaniraj/archive/2008/07/17/set-based-operations-in-ado-net-data -services.aspx
sumber
Terima kasih banyak. Metode ekstensi WhereIn sudah cukup bagi saya. Saya membuat profil dan menghasilkan perintah SQL yang sama ke DataBase sebagai e-sql.
public Estado[] GetSomeOtherMore(int[] values) { var result = _context.Estados.WhereIn(args => args.Id, values) ; return result.ToArray(); }
Hasilkan ini:
SELECT [Extent1].[intIdFRLEstado] AS [intIdFRLEstado], [Extent1].[varDescripcion] AS [varDescripcion] FROM [dbo].[PVN_FRLEstados] AS [Extent1] WHERE (2 = [Extent1].[intIdFRLEstado]) OR (4 = [Extent1].[intIdFRLEstado]) OR (8 = [Extent1].[intIdFRLEstado])
sumber
Saya pikir Bergabung di LINQ bisa menjadi panduan.
Saya belum menguji kodenya. Semoga membantu. Bersulang. :-)
List<long?> txnIds = new List<long?>(); // Fill list var q = from t in svc.OpenTransaction join tID in txtIds on t equals tID select t;
Bergabunglah di LINQ:
http://weblogs.asp.net/salimfayad/archive/2008/07/09/linq-to-entities-join-queries.aspx
sumber
Maaf pengguna baru, saya akan mengomentari jawaban yang sebenarnya, tetapi sepertinya saya belum bisa melakukannya?
Bagaimanapun, sehubungan dengan jawaban dengan kode sampel untuk BuildContainsExpression (), ketahuilah bahwa jika Anda menggunakan metode itu pada Entitas database (yaitu bukan objek dalam memori) dan Anda menggunakan IQuerable, itu sebenarnya harus pergi ke database karena pada dasarnya ia melakukan banyak SQL "atau" kondisi untuk memeriksa klausa "where in" (jalankan dengan SQL Profiler untuk melihat).
Ini bisa berarti, jika Anda menyempurnakan IQuer dapat dengan beberapa BuildContainsExpression (), itu tidak akan mengubahnya menjadi satu pernyataan SQL yang dijalankan di akhir seperti yang Anda harapkan.
Solusi bagi kami adalah menggunakan beberapa gabungan LINQ untuk menyimpannya ke satu panggilan SQL.
sumber
Selain jawaban yang dipilih.
Ganti
Expression.Or
denganExpression.OrElse
untuk digunakan dengan Nhibernate dan perbaikiUnable to cast object of type 'NHibernate.Hql.Ast.HqlBitwiseOr' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'
pengecualian.sumber