我了解此问题已得到解答,并且我同意使用 AsEnumerable() 是可行的方法。不过,我想强调一下我经常遇到的一个常见场景,即 AsEnumerable() 用于解决此错误的效率很低。
来自.NET Language-Integrated Query for Relational Data
与 ToList() 和 ToArray() 不同,AsEnumerable() 运算符不会导致执行查询。它仍然被推迟。 AsEnumerable() 运算符仅更改查询的静态类型,将 IQueryable 转换为 IEnumerable,诱使编译器将查询的其余部分视为本地执行。
参考文献
- Am I misunderstanding LINQ to SQL .AsEnumerable()?
- Understanding .AsEnumerable() in LINQ to SQL
低效的方式
IEnumerable<InvoiceDTO> inefficientEnumerable =
(from a in db.Invoices
where a.Practice_Key == practiceKey.FirstOrDefault()
select a
).AsEnumerable().
Select(x => new InvoiceDTO
{
InvoiceID = x.InvoiceID,
PracticeShortName = x.Dim_Practice.Short_Name,
InvoiceDate = x.InvoiceDate,
InvoiceTotal = x.InvoiceAmount,
IsApproved = x.IsApproved,
InvoiceStatus = (
x.IsApproved == null ? "Pending" :
x.IsApproved == true ? "Approved" :
x.IsApproved == false ? "Rejected" : "Unknown"
),
InvoicePeriodStartDateText = x.InvoicePeriodStart.ToShortDateString(),
InvoicePeriodEndDateText = x.InvoicePeriodEnd.ToShortDateString(),
InvoicePeriodStartDate = x.InvoicePeriodStart,
InvoicePeriodEndDate = x.InvoicePeriodEnd
}
);
invoices = inefficientEnumerable.ToList();
这里AsEnumerable 用于整个表。尽管不需要,但所有列都被选中。
更好的方法
IQueryable<InvoiceDTO> invoicesQuery =
(from a in db.Invoices
where a.Practice_Key == practiceKey.FirstOrDefault()
select new InvoiceDTO
{
InvoiceID = a.InvoiceID,
PracticeShortName = a.Dim_Practice.Short_Name,
InvoiceDate = a.InvoiceDate,
InvoiceTotal = a.InvoiceAmount,
IsApproved = a.IsApproved,
InvoiceStatus = (
a.IsApproved == null ? "Pending" :
a.IsApproved == true ? "Approved" :
a.IsApproved == false ? "Rejected" :"Unknown"
),
InvoicePeriodStartDate = a.InvoicePeriodStart,
InvoicePeriodEndDate = a.InvoicePeriodEnd
});
IEnumerable<InvoiceDTO> betterEnumerable = invoicesQuery.AsEnumerable().
Select(x => new InvoiceDTO
{
InvoiceID = x.InvoiceID,
PracticeShortName = x.PracticeShortName,
InvoiceDate = x.InvoiceDate,
InvoiceTotal = x.InvoiceTotal,
IsApproved = x.IsApproved,
InvoiceStatus = x.InvoiceStatus,
InvoicePeriodStartDateText = x.InvoicePeriodStartDate.ToShortDateString(),
InvoicePeriodEndDateText = x.InvoicePeriodEndDate.ToShortDateString(),
InvoicePeriodStartDate = x.InvoicePeriodStartDate,
InvoicePeriodEndDate = x.InvoicePeriodEndDate
}
);