LINQ 谓词中使用的集合范围
我真的很喜欢 PredicateBuilder。它允许我非常动态地构建各种查询。谓词变量可以传递给不同的对象,并且它们可以添加它们知道的值等。除非我需要在散列集合上使用 .Contains 。嗡!崩溃和燃烧。
例如(示例/伪代码,这可能会或可能不会编译/运行):
protected Expression<Func<MyClass, bool>> GetWherePredicate()
{
string[] selectedValues = Request.Form.GetValues("checkbox1") ?? new string[0];
HashSet<int> selectedIDs = new HashSet<int>(selectedValues.Cast<int>());
Expression<Func<MyClass, bool>> predicate = PredicateBuilder.True<MyClass>();
predicate = predicate.And(s => selectedIDs.Contains(s.ID));
return predicate;
}
protected void Retrieve()
{
Expression<Func<MyClass, bool>> predicate = GetWherePredicate();
IEnumerable<MyClass> retrievedValues = MyDataContext.GetTable<MyClass>.Where(predicate);
}
当我尝试这样做时,我得到一个 NotSupportedException:方法'Boolean Contains(Int32)'没有支持对 SQL 的翻译 由于 selectedIDs HashSet 不在范围内。如果我用同样的方法完成这一切,那么效果就很好。
我需要知道正确的方法来让我的谓词在那里解析或编译或其他什么,以便它可以在声明 HashSet 的不同范围内使用。有什么帮助吗?
更新:我错了。下面的代码工作正常,因此不存在范围冲突。谢谢杰伊。
string[] selectedValues = Request.Form.GetValues("checkbox1") ?? new string[0];
Expression<Func<MyClass, bool>> predicate = PredicateBuilder.True<MyClass>();
predicate = predicate.And(s => selectedValues.Contains(s.ID.ToString()));
I really like PredicateBuilder. It allows me to build all sorts of queries very dynamically. The predicate variable can be passed around to different objects and they can add onto it with values they know about, etc. Except when I am needing to use a .Contains on a hashed collection. Bzzt! Crash and burn.
For instance (example/pseudo code, this may or may not compile/run):
protected Expression<Func<MyClass, bool>> GetWherePredicate()
{
string[] selectedValues = Request.Form.GetValues("checkbox1") ?? new string[0];
HashSet<int> selectedIDs = new HashSet<int>(selectedValues.Cast<int>());
Expression<Func<MyClass, bool>> predicate = PredicateBuilder.True<MyClass>();
predicate = predicate.And(s => selectedIDs.Contains(s.ID));
return predicate;
}
protected void Retrieve()
{
Expression<Func<MyClass, bool>> predicate = GetWherePredicate();
IEnumerable<MyClass> retrievedValues = MyDataContext.GetTable<MyClass>.Where(predicate);
}
When I try to do that, I get a NotSupportedException: Method 'Boolean Contains(Int32)' has no supported translation to SQL due to the selectedIDs HashSet not being in scope. If I do this all in the same method, then it works fine.
I need to know the right way to get my predicate there to resolve or compile or whatever so that it can be used in a different scope from where the HashSet is declared. Any help?
UPDATE: I had this pretty wrong. The code below works fine, so there is no scope conflict. Thanks Jay.
string[] selectedValues = Request.Form.GetValues("checkbox1") ?? new string[0];
Expression<Func<MyClass, bool>> predicate = PredicateBuilder.True<MyClass>();
predicate = predicate.And(s => selectedValues.Contains(s.ID.ToString()));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
从您引用的例外情况来看,范围似乎不太可能是这里的一个因素。
我对此的回答是,您需要将
selectedIDs
声明为IEnumerable
而不是HashSet
(或者在调用之前将其强制转换)Contains()
,但这并不能说明它在同一方法中工作,所以我不确定如果没有看到任何表现出这种行为的实际代码,就很难进行故障排除。任何进一步。
From the exception you cite, it seems unlikely that scope is a factor here.
My answer to this is that you need to declare
selectedIDs
asIEnumerable<int>
instead ofHashSet<int>
(or just cast it before callingContains()
, but that doesn't account for it working when all in the same method, so I'm unsure.Without seeing any actual code that is exhibiting this behaviour, it will be difficult to troubleshoot any further.
不要被
Contains
这个名字弄得眼花缭乱……有很多方法都是这样命名的,但支持 SQL 转换的方法并不多。Enumerable.Contains
和List.Contains
是支持翻译的方法。HashSet.Contains
是一种不支持翻译的方法。有很多解决方案,但我建议:
虽然更简单的解决方案可能是:
编辑:它根本不是关于 Contains 的具体实现。这是关于 linqtosql 查询提供程序是否可以识别该方法并将其转换为 IN(列表)sql 表达式。识别代码查看表达式中使用的参数类型。识别代码不使用多态性/实现,也不遍历继承树寻找其他可能性。
即使这些参数引用同一实例,由于参数的类型不同,也会出现不同的转换行为。
.Contains()
在翻译时不会被调用,因此它的实现是无关紧要的。它可以抛出NotImplementedException
或返回true;
Do not get razzle-dazzled by the name
Contains
... there are many methods that are named that, and not many have supported translations into SQL.Enumerable.Contains<T>
andList<T>.Contains
are methods with supported translations.HashSet<T>.Contains
is a method that has no supported translation.There are many resolutions, but I recommend:
Although a simpler solution might be:
Edit: It's not about concrete implementation of Contains at all. It's about whether the linqtosql query provider can identify the method and translate it into an IN (list) sql expression. The recognition code looks at the type of the parameter used in the expression. The recognition code does not use polymorphism/implementation nor does it walk the inheritence tree looking for other possibilities.
Even though these parameters reference the same instance, different translation behaviors occur because the type of the parameter is different.
.Contains()
is not called as it is translated, therefore its implementation is irrelevant. It couldthrow NotImplementedException
orreturn true;