如何在LINQ语句中使用Extension方法
本文关键字:Extension 方法 语句 LINQ | 更新日期: 2023-09-27 18:11:23
我有一个扩展方法将Address
转换成一个在线字符串:
public static class AddressExtensions
{
public static string ToOneLine(this Address address)
{
var sb = new StringBuilder();
sb.Append(address.Street);
if (!string.IsNullOrWhiteSpace(address.City)) sb.Append(string.Format("{0}, ",address.City));
if (!string.IsNullOrWhiteSpace(address.State)) sb.Append(string.Format("{0}, ", address.State));
if (!string.IsNullOrWhiteSpace(address.Zip)) sb.Append(string.Format("{0}, ", address.Zip));
return sb.ToString();
}
}
然后我使用它将数据从域模型传输到我的DTO。下面的代码使用foreach
并且工作良好:
var entity=_repository.GetAll();
var model = new List<SummaryViewModel>();
foreach (var e in entity)
{
model.Add(new SummaryViewModel
{
Address = e.Address.ToOneLine(),
Name = e.Name,
Id = e.Id
});
}
但当使用LINQ
时,
var model = entity.Select(e => new SummaryViewModel
{
Address = e.Address.ToOneLine(), Id = e.Id
}).ToList();
我得到了一个System.NotSupportedException
。
LINQ to Entities does not recognize the method 'System.String ToOneLine
(Domain.Models.Address)' method, and this method cannot be translated
into a store expression.
发生了什么事?我想这两种方法都可以。
在LINQ语句中使用我的扩展方法的正确方法是什么?
因为EF无法将该扩展方法转换为SQL。修复它的最简单方法是使用AsEnumerable()
(这实际上是foreach
所做的)切换到链接到对象:
var model = entity.AsEnumerable()
.Select(e => new SummaryViewModel
{
Address = e.Address.ToOneLine(), Id = e.Id
}).ToList();
与ToList
不同,使用AsEnumerable
不会在内存中创建额外的集合,它只是将Linq调用绑定到Enumerable
而不是Queryable
,因此映射是在内存中完成的,而不是在SQL中。
解析查询,然后映射。
var model = entity.ToList().Select(e => new SummaryViewModel
{
Address = e.Address.ToOneLine(), Id = e.Id
}).ToList();
现在,通过使用延迟执行,数据库正在尝试解释您的ToOneLine()扩展方法。通过使用ToList()立即解析它,您可以正确地遍历服务器上的集合并将其映射到您的模型。
这一行:
foreach (var e in entity)
隐式地做与.AsEnumerable()
相同的事情。当使用linq表达式LINQ2Entities试图将其转换为数据库表达式时,枚举并从数据库中取出对象。在模型作用域之外执行。
对于foreach
实际做什么的更深入的描述,请查看c#中的foreach循环是如何工作的?实际上,entity
不一定是IEnumerable<T>
,它只需要实现GetEnumerator()
。酷,不是吗?:)
我在你的解决方案,做
var model = entity.AsEnumerable().Select(e => new SummaryViewModel
{
Address = e.Address.ToOneLine(), Id = e.Id
}).ToList();