C# 从linq查询调用方法会抛出;在上一个操作完成之前,在此上下文上启动了第二个操作;
给定此示例伪代码:C# 从linq查询调用方法会抛出;在上一个操作完成之前,在此上下文上启动了第二个操作;,c#,linq,asp.net-core,C#,Linq,Asp.net Core,给定此示例伪代码: var student = from s in ctx.Students where s.StudentName == "Bill" let code = GetCode(s.Id) select new { Name = s.StudentName, Code = code.Code
var student = from s in ctx.Students
where s.StudentName == "Bill"
let code = GetCode(s.Id)
select new
{
Name = s.StudentName,
Code = code.Code
};
private Code GetCode(int id)
{
return ctx.Codes.FirstOrDefault(x => x.Id == id);
}
我收到以下错误消息:
“在上一个操作之前,在此上下文上启动了第二个操作
操作已完成。这通常是由使用
DbContext的同一实例,但实例成员不是
保证线程安全。这也可能是由嵌套
正在客户端上计算的查询,如果是这种情况,请重写
避免嵌套调用的查询。“
但是,如果我在let子句中明确地编写查询,它就可以工作了:
var student = from s in ctx.Students
where s.StudentName == "Bill"
let ctx.Codes.FirstOrDefault(x => x.Id == s.Id)
select new
{
Name = s.StudentName,
Code = code.Code
};
有没有一种方法可以调用GetCode方法而不出现任何错误?我假设您使用的是EF。我的假设/解释是:通过LINQ创建的
IQueryable
将通过编译成SQL。EF不知道如何将您的GetCode
转换为SQL,它被作为查询中的last
语句进行处理,因此它可以对其求值并尝试对DB进行查询,它发现您的上下文中已经开始了一个操作(正在生成第一个SQL)。但在第二种情况下,它可以将您的查询完全转换为SQL并对db进行一次调用。我假设您使用的是EF。我的假设/解释是:通过LINQ创建的IQueryable
将通过编译成SQL。EF不知道如何将您的GetCode
转换为SQL,它被作为查询中的last
语句进行处理,因此它可以对其求值并尝试对DB进行查询,它发现您的上下文中已经开始了一个操作(正在生成第一个SQL)。但在第二种情况下,它可以将您的查询完全转换为SQL并对db进行一次调用。这是一个与SQL相关的问题。where后面的条件在服务器上运行,并且服务器端没有定义GetCode
方法,因此服务器端无法识别GetCode方法并导致错误
请参阅
解决方案是在客户机上执行整个SQL语句,并将ctx.Students
转换为一个集合表单ctx.Students.ToList()
这是一个与之相关的问题。where后面的条件在服务器上运行,并且服务器端没有定义GetCode
方法,因此服务器端无法识别GetCode方法并导致错误
请参阅
解决方案是在客户机上执行整个SQL语句,并将ctx.Students
转换为一个集合表单ctx.Students.ToList()
扔掉GetCode
并使用join
更有效。更改方法签名:code-GetCode(YourContext-ctx,int-id)
@Dennis这是一个示例代码-我的查询更多complex@AlexanderPetrov我试过了,结果也一样error@user441365:查询复杂性如何阻止您使用联接?第二个示例有效,但它会导致子查询。从数据库的角度来看,这是非常低效的。丢弃GetCode
并使用join
更有效。更改方法签名:code-GetCode(YourContext-ctx,int-id)
@Dennis这是一个示例代码-我的查询更多complex@AlexanderPetrov我试过了,结果也一样error@user441365:查询复杂性如何阻止您使用联接?第二个示例有效,但它会导致子查询。从数据库的角度来看,这是非常低效的。谢谢你的解释-有什么办法可以让我调用函数吗?@user441365无法从我的头脑中找到一个优雅的解决方案,但是你可以尝试实现一个令人讨厌的方法,比如感谢你的解释——有没有办法让我调用一个函数?@user441365无法从我的头脑中找到一个优雅的解决方案,但是你可以尝试实现一个令人讨厌的方法,比如
var student = from s in ctx.Students.ToList()
where s.StudentName == "Bill"
let code = GetCode(s.Id)
select new
{
Name = s.StudentName,
Code = code.Code
};