在选择中调用函数时,出现此错误:在上一个操作完成之前,已在此上下文上启动了第二个操作。
public bool func2(int ID)
{
return (from t2 in _odc.table2
where t2.ID == ID &&
(t2.col1 > 0 ||
t2.col2 != "" ||
t2.col3 != "")
select t2
).Any();
}
public List<MyModel> func1()
{
return (from t1 in _odc.t1
join t3 in _odc.t3 on t1.ID equals t3.ID
where t1.col2 > 300
where t1.col3 != 1
where t1.col4 != 285
where t1.col5 != 830
where t1.col6 > 0
select new MyModel
{
ID = t1.ID,
isFunc2 = func2(t1.ID),
}).ToList();
}
我可以这样做吗,还是必须在foreach函数中调用func2? (已经对其进行了测试,并且可以与foreach一起使用。)
答案 0 :(得分:0)
您必须意识到您的查询实现了IQueryable<...>
。
实现IQueryable
的对象有一个Expression
和一个Provider
。 Expression
是必须查询内容的通用表示。 Provider
知道谁必须执行查询以及该执行者使用哪种语言。
当您开始枚举IQueryable
表示的序列时(=调用.ToList()
时),Expression
被发送到Provider
。 Provider
会将Expression
转换为必须执行查询的过程所能理解的语言(通常是SQL)并将其发送给执行过程。
返回的数据放入实现IEnumerable<...>
的对象中,并枚举该对象。
问题在于,提供程序仅知道如何将相当基本的Expressions
转换为SQL。它不知道如何翻译Func2
。
我没有看到您在查询中使用任何T3项目。那是打字错误吗?
无论如何,最简单的解决方案是将Func2的代码放入Func1:
(与LINQ查询语法相比,我对LINQ方法语法更熟悉,但是您将了解要点)
var result = dbContext.T1
// don't take all T1 items, but only the ones where:
.Where(t1 => t1.col2 > 300
&& t1.col3 != 1
&& t1.col4 != 285
&& t1.col5 != 830
&& t1.col6 > 0
// join the remaining t1s with table T3
.Join dbContext.T3,
t1 => t1.Id, // from every T1 take the id
t3 => t3.Id, // from every T3 take the id
// ResultSelector: take a t1 and a matching t3 to create one new object
(t1, t3) => new MyModel
{
Id = t1.Id,
// IsFunc2: true if Table2 has any element with Id equal to t1.Id and col values
IsFunc2 = dbContext.Table2
.Where(t2 => t2.ID == t1.Id
&& (t2.col1 > 0 || t2.col2 != "" || t2.col3 != ""))
.Any();
});
如果经常在各种不同的Expressions中使用Func2,则可以考虑对Func2进行转换,使其以IQueryable作为输入。
我将其创建为IQueryable<Table2Row>
的扩展功能。参见extension methods demystified
static bool Func2(this IQueryable<Table2Row> rows, int id)
{
return rows
.Where(row => row.ID == id && (row.col1 > 0 || row.col2 != "" || row.col3 != ""))
.Any();
}
现在,您可以在联接的ResultSelector中使用它:
(t1, t3) => new MyModel
{
Id = t1.Id,
IsFunc2 = dbContext.Table2.Func2(t1.Id),
});