将此语句转换为linq

  • 本文关键字:linq 转换 语句 c# linq
  • 更新时间 :
  • 英文 :


我是LINQ的新手。是否可以将此语句转换为LINQ语句?

var jobs = (from a in auditData.AsEnumerable()
join b in _dbContext.Jobs.AsEnumerable() on a.JobId equals b.Id.ToString()
select new { a, b.JobId }).ToList(); 
foreach (var job in jobs) {
foreach (var audit in auditData)
{
if(job.a.Id == audit.Id)
{
audit.JobId = job.JobId;
break;
}
}
}

我相信有一种方法可以把这个转换成LINQ语句。但我不知道该怎么做。有人能帮我一下吗?

LINQ是一种技术。在此基础上实现了EF, EF Core, linq2db, LinqToSQL等。

假设您正在使用EF Core

你不能用EF Core有效地做到这一点。你必须将记录加载到内存中并更新它们,就像你在问题中所做的那样。

但是EF Core的扩展可以改善这一任务。例如linq2db。EntityFrameworkCore(免责声明:我是创建者之一)

var auditToUpdate = 
from a in auditData
join b in _dbContext.Jobs on Convert.ToInt32(a.JobId) equals b.Id
select new { a, b }; 
auditToUpdate
.Set(u => u.a.JobId, u => u.b.JobId)
.Update();

我将尝试一下这个问题,因为在我早期的工作中,我也有同样的问题,关于我们如何可能使用LINQ在管道中做事情。下面的内容可能行不通,因为我需要的信息太少了,但它应该有足够的信息让你能够自己完成这项工作:

//Run an IN query on SQL end and get jobs that match our auditData JobIds
var firstUpdatedJob = _dbContext.Jobs.Where(job => auditData.Select(audit => audit.JobId).Contains(job.Id.ToString()))
//Get all the Job Ids that matched - there's no need to get audit back because this matches 100% on auditData
.Select(job => job.Id)
//Switch from EF to Linq2Objects
.AsEnumerable()
//Inner join on Audit Data and we'll have all the jobs we care about with a match in DB
.Join(auditData, jobId => jobId, audit => audit.Id, (jobId, audit) => {
//This is what you were doing in foreach when you matched
audit.JobId = jobId;
//we must return a result. I'm choosing to return audit
return audit;
})
//VERY IMPORTANT: LINQ is Lazy. None of the above will execute unless you force it somehow.
//Coincidentally because of your break, FirstOrDefault will be equivalent which also forces execution
//And will cause the side effect to take place
.FirstOrDefault();

上面是作为转换管道构建的单个语句。如果您真的想处理所有auditData,您应该删除FirstOrDefault(),而使用强制执行完整集合计算的方法。如果您只想强制求值而不需要收集本身,则可以选择Count()。或者,你可以使用ToArray()代替,如果你想转换后的编辑回来。

考虑到您的auditData正在通过副作用进行修改,您不需要创建集合的另一个副本,您可以使用auditData,因为它是更新JobId的下一步。

UPDATE:我看过其他贡献者对这个问题的回答,他们比我的好得多,但是,如果你有时间,你可以把它当作一个有趣的补充来读。

LINQ帮助您从现有的ienumerble中构造ienumerble,而不是更改现有的ienumerble(为此循环是完美的)。它通过提供可以组合的基本规则来实现这一点。例如:

var l = new List<int>(new[] { 0, 1, 2 });
var e = from item in l where item > 0 select item;
Console.WriteLine(string.Join(", ", e));
l.Add(3);
Console.WriteLine("Added value: 3");
Console.WriteLine(string.Join(", ", e));

这会产生以下输出:

1, 2
Added value: 3
1, 2, 3

让我们逐行查看:

  1. 我们用元素0,1,2创建一个列表
  2. 我们用规则创建一个IEnumerable: "select all items from list 1,该值大于0">
  3. 检查创建的IEnumerable的内容:1,2
  4. 我们添加值3
  5. 我们再次检查内容,看到IEnumerable更新了。但是为什么呢?

因为IEnumerable存储了RULE,所以当我们从它构造字符串来输出它的值时,我们实际上说,"选择列表1中大于0的所有项">

所以LINQ基本上是这样做的:通过告诉一个规则,从现有的IEnumerables中构建新的IEnumerables,根据这个规则,我们可以在每次查询它的项时更新它。

注意:如果你想将IEnumerable保存在当前状态,只需调用:

e.ToArray();

这将用e的当前值创建一个新的数组,它不再依赖于列表1的更改。一个例子:

var l = new List<int>(new[] { 0, 1, 2 });
var e = from item in l where item > 0 select item;
var a = e.ToArray();
Console.WriteLine(string.Join(", ", e));
Console.WriteLine(string.Join(", ", a));
l.Add(3);
Console.WriteLine("Added value: 3");
Console.WriteLine(string.Join(", ", e));
Console.WriteLine(string.Join(", ", a));

输出:

1, 2
1, 2
Added value: 3
1, 2, 3
1, 2

我希望这将帮助你。如果不是,只要注意,你的代码是正确的,你不需要修改它,当然,欢迎提问。

最新更新