“包含()”解决方法使用Linq到实体?

我试图创建一个查询使用where子句中的id列表,使用Silverlight ADO.Net数据服务客户端api(因此Linq To Entities)。 有谁知道的解决方法包含不被支持?

我想要做这样的事情:

List<long?> txnIds = new List<long?>(); // Fill list var q = from t in svc.OpenTransaction where txnIds.Contains(t.OpenTransactionId) select t; 

试过这个:

 var q = from t in svc.OpenTransaction where txnIds.Any<long>(tt => tt == t.OpenTransactionId) select t; 

但是得到了“方法”Any“不被支持”。

更新: EF≥4直接支持Contains (Checkout Any ),所以您不需要任何解决方法。

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

用法:

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

你可以重新编写一些e-sql(注意关键字“it”):

 return CurrentDataSource.Product.Where("it.ID IN {4,5,6}"); 

以下是我用来从集合YMMV生成一些e-sql的代码:

 string[] ids = orders.Select(x=>x.ProductID.ToString()).ToArray(); return CurrentDataSource.Products.Where("it.ID IN {" + string.Join(",", ids) + "}"); 

来自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); } 

查询变成:

 var query2 = context.Entities.Where(BuildContainsExpression<Entity, int>(e => e.ID, ids)); 

我不确定Silverligth,但在LINQ到对象我总是使用任何()这些查询。

 var q = from t in svc.OpenTranaction where txnIds.Any(t.OpenTransactionId) select t; 

为了完成记录,这是我最后使用的代码(错误检查省略了清晰)…

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

下面是一个演示如何使用DataServiceContext编写基于集合的查询的示例: http : //blogs.msdn.com/phaniraj/archive/2008/07/17/set-based-operations-in-ado-net-data -services.aspx

非常感谢。 Where扩展方法对我来说是足够的。 我对其进行了剖析,并生成了与e-sql相同的SQL命令到DataBase。

 public Estado[] GetSomeOtherMore(int[] values) { var result = _context.Estados.WhereIn(args => args.Id, values) ; return result.ToArray(); } 

生成此:

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

我认为加入LINQ可以是一个解决方案。

我还没有测试代码。 希望它有帮助。 干杯。 🙂

 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; 

加入LINQ:

http://weblogs.asp.net/salimfayad/archive/2008/07/09/linq-to-entities-join-queries.aspx

对不起新用户,我会对实际的答案进行评论,但似乎我不能做到这一点呢?

无论如何,关于BuildContainsExpression()的示例代码的答案,请注意,如果您在数据库实体(即不是内存中的对象)上使用该方法,并且您正在使用IQueryable,则实际上必须切换到数据库因为它基本上做了很多SQL“或”条件来检查“where in”子句(用SQL Profiler运行它来查看)。

这可能意味着,如果您正在使用多个BuildContainsExpression()来提炼IQueryable,那么它将不会将其转换为一个如您所期望的那样在最后运行的SQL语句。

我们的解决方法是使用多个LINQ连接来保持一个SQL调用。

除了选定的答案。

Expression.Or替换为Expression.OrElse以与Nhibernate一起使用,并修复Unable to cast object of type 'NHibernate.Hql.Ast.HqlBitwiseOr' to type 'NHibernate.Hql.Ast.HqlBooleanExpression'异常。