C# LINQ谓词中使用的集合的范围

C# LINQ谓词中使用的集合的范围,c#,linq-to-sql,predicatebuilder,C#,Linq To Sql,Predicatebuilder,我真的很喜欢。它允许我非常动态地构建各种查询。谓词变量可以传递给不同的对象,它们可以使用它们知道的值等添加到谓词变量中,除非我需要在散列集合上使用.Contains。Bzzt!碰撞和燃烧 例如(示例/伪代码,可能编译/运行,也可能不编译/运行): 受保护的表达式GetWherePredicate() { string[]selectedValues=Request.Form.GetValues(“复选框1”)??新字符串[0]; HashSet selectedds=新的HashSet(sele

我真的很喜欢。它允许我非常动态地构建各种查询。谓词变量可以传递给不同的对象,它们可以使用它们知道的值等添加到谓词变量中,除非我需要在散列集合上使用.Contains。Bzzt!碰撞和燃烧

例如(示例/伪代码,可能编译/运行,也可能不编译/运行):

受保护的表达式GetWherePredicate()
{
string[]selectedValues=Request.Form.GetValues(“复选框1”)??新字符串[0];
HashSet selectedds=新的HashSet(selectedValues.Cast());
表达式谓词=PredicateBuilder.True();
谓词=谓词。和(s=>selectedIDs.Contains(s.ID));
返回谓词;
}
受保护的void检索()
{
表达式谓词=GetWherePredicate();
IEnumerable retrievedValues=MyDataContext.GetTable.Where(谓词);
}
当我尝试这样做时,我得到一个NotSupportedException:Method'Boolean Contains(Int32)'不支持转换为SQL,因为SelectedDS哈希集不在范围内。如果我用同样的方法做这一切,那么效果很好

我需要知道正确的方法,让我的谓词在那里解析、编译或其他任何东西,以便它可以在声明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()));
string[]selectedValues=Request.Form.GetValues(“checkbox1”)??新字符串[0];
表达式谓词=PredicateBuilder.True();
predicate=predicate.And(s=>selectedValues.Contains(s.ID.ToString());

从您引用的例外情况来看,范围似乎不太可能是一个因素

我的答案是,您需要将
selectedIDs
声明为
IEnumerable
,而不是
HashSet
(或者在调用
Contains()
之前强制转换它),但这并不能解释它在使用相同方法时是否工作,因此我不确定


如果看不到任何实际的代码表现出这种行为,就很难进一步排除故障。

不要被
包含的名称弄得眼花缭乱。
有许多方法都被命名为该方法,并且没有多少方法支持转换为SQL

  • Enumerable.Contains
    List.Contains
    是支持翻译的方法
  • HashSet.Contains
    是一个不支持翻译的方法

有很多决议,但我建议:

IEnumerable<string> selectedValueQuery =
  Request.Form.GetValues("checkbox1") ?? Enumerable.Empty<string>();
List<string> selectedIds = selectedValueQuery
  .Cast<int>()
  .Distinct()
  .ToList();
IEnumerable selectedValueQuery=
Request.Form.GetValues(“checkbox1”)??Enumerable.Empty();
列表SelectedDS=selectedValueQuery
.Cast()
.Distinct()
.ToList();
尽管更简单的解决方案可能是:

IEnumerable<int> selectedIDs = new HashSet<int>(selectedValues.Cast<int>()); 
IEnumerable selectedIDs=新哈希集(selectedValues.Cast());

编辑:这根本不是关于包含的具体实现,而是关于linqtosql查询提供程序是否能够识别该方法并将其转换为IN(列表)sql表达式。识别代码查看表达式中使用的参数的类型。识别代码不使用多态性/实现,也不在继承树中查找其他可能性

List<int> myList = new List<int>(){1, 2, 3};
IList<int> myIList = myList;
IEnumerable<int> myIEnumerable = myList;

  //works by List<T>.Contains()
db.Customers.Where(c => myList.Contains(c.CustomerID));

  //doesn't work, no translation for IList<T>.Contains
db.Customers.Where(c => myIList.Contains(c.CustomerID));

  //works by Enumerable.Contains<T>()
db.Customers.Where(c => myIEnumerable.Contains(c.CustomerID));

  //works by Enumerable.Contains<T>()
db.Customers.Where(c => Enumerable.Contains(myIEnumerable, c.CustomerID));
List myList=newlist(){1,2,3};
IList myIList=myList;
IEnumerable myIEnumerable=myList;
//按列表工作。包含()
其中(c=>myList.Contains(c.CustomerID));
//不起作用,没有IList的翻译。包含
其中(c=>myIList.Contains(c.CustomerID));
//按可枚举项工作。包含()
其中(c=>myIEnumerable.Contains(c.CustomerID));
//按可枚举项工作。包含()
其中(c=>Enumerable.Contains(myIEnumerable,c.CustomerID));
即使这些参数引用了相同的实例,但由于参数的类型不同,也会出现不同的转换行为


.Contains()
在翻译时不被调用,因此它的实现是不相关的。它可以
抛出NotImplementedException
返回true;

好的,我会仔细研究一下我的代码,看看我是否走错了路。谢谢。很好,谢谢。我花了一些时间阅读了IEnumerable.Contains之间的区别还有IList.Contains,我想这可能是我一开始讨论的核心问题。所以你推荐的类型都是很好的指南。IList.Contains没有支持的翻译。List.Contains有。没有IEnumerable.Contains这样的东西。这是一个随意的评论,我是根据记忆写名字的。我没有试图为人们记录东西。有时es这个网站和其他任何东西一样让我烦恼…/叹气,我通常不会对class.methods名称这么敏感,但这是导致原始问题的原因。我不认为这是松弛。这是缺乏知识。现在我知道IEnumerable有Enumerable。包含与LINQ一起工作的扩展方法。HashSet实现了I实现ICollection的列表,它有一个Contains方法,不能与LINQ一起工作。所以从技术上来说,你和你说的我一样不正确,这很讽刺,你不觉得吗?
List<int> myList = new List<int>(){1, 2, 3};
IList<int> myIList = myList;
IEnumerable<int> myIEnumerable = myList;

  //works by List<T>.Contains()
db.Customers.Where(c => myList.Contains(c.CustomerID));

  //doesn't work, no translation for IList<T>.Contains
db.Customers.Where(c => myIList.Contains(c.CustomerID));

  //works by Enumerable.Contains<T>()
db.Customers.Where(c => myIEnumerable.Contains(c.CustomerID));

  //works by Enumerable.Contains<T>()
db.Customers.Where(c => Enumerable.Contains(myIEnumerable, c.CustomerID));