如何在LINQ语句中使用Extension方法?

时间:2014-07-03 15:05:39

标签: c# linq entity-framework foreach

我有一种将Address转换为oneline字符串的扩展方法:

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语句中使用扩展方法的正确方法是什么?

3 个答案:

答案 0 :(得分:6)

Becasue EF无法将该扩展方法转换为SQL。解决问题的最简单方法是使用AsEnumerable()转换为Linq-to-Objects(这实际上是foreach所做的):

var model = entity.AsEnumerable()
                  .Select(e => new SummaryViewModel
{
    Address = e.Address.ToOneLine(), Id = e.Id
}).ToList();

ToList不同,使用AsEnumerable不会在内存中创建额外的集合,它只是将Linq调用绑定到Enumerable而不是Queryable,因此映射已完成在内存中而不是在SQL中。

答案 1 :(得分:0)

解析您的查询,然后映射它。

var model = entity.ToList().Select(e => new SummaryViewModel
    {
        Address = e.Address.ToOneLine(), Id = e.Id
    }).ToList();

目前,通过使用延迟执行,数据库正在尝试解释您的ToOneLine()扩展方法。通过使用ToList()立即解析它,您可以正确地迭代服务器上的集合并将其映射到您的模型。

答案 2 :(得分:0)

这一行:

foreach (var e in entity)

隐含地与.AsEnumerable()做同样的事情。当使用LINQ表达式LINQ2Entities尝试将其转换为数据库表达式时,会从数据库中枚举并拉出对象。即在模型范围之外执行它。

要更深入地了解foreach实际执行的操作,请查看How do foreach loops work in C#?,实际上entity不一定是IEnumerable<T>,只需要实现GetEnumerator()。很酷,对吧? :)

即在你的解决方案中,做

var model = entity.AsEnumerable().Select(e => new SummaryViewModel
    {
        Address = e.Address.ToOneLine(), Id = e.Id
    }).ToList();

会解决问题。