在 LINQ 中调用方法

Calling a Method inside LINQ

我有这样的东西:

var adrsQuery = (from a in this.Context.Addresses
            where myList.Contains(a.Address_K)
            select new AlternateAddressesDB()
            {
                Line1 = GetAddressLine1(a.AddressLine1),
                Line2 = a.AddressLine2,
                City = a.City,
                State = a.State,
                ZipCode = a.ZipCode
            }).ToList();


        private static string GetAddressLine1(string adrs)
        {
            if (string.IsNullOrWhiteSpace(adrs))
                adrs = "Medical Office";

            return adrs;
        }

问题出在Line1 = GetAddressLine1(a.AddressLine1), 看起来我不能在那里调用方法,我如何在不那样调用的情况下执行方法中的逻辑?

问题不在于 LINQ。您正在使用 ORM 将您正在编写的 LINQ 翻译成 SQL。它不能翻译任意方法调用。您需要对查询结果进行转换。

因此 - 无需 尝试内联调用 GetAddressLine1 即可获得结果 。然后您可以使用 Select 再次投影结果以修复您的数据...例如:

var adrsQuery = this.Context.Addresses
.Where(a => myList.Contains(a.Address_K))
.AsEnumerable()
.Select(a => new AlternateAddressesDB
    {
        Line1 = GetAddressLine1(a.AddressLine1),
        Line2 = a.AddressLine2,
        City = a.City,
        State = a.State,
        ZipCode = a.ZipCode
    }).ToList();


private static string GetAddressLine1(string adrs)
{
    if (string.IsNullOrWhiteSpace(adrs))
        adrs = "Medical Office";

    return adrs;
}

我认为关键是 this.Context,我认为这是某种形式。所以你的 linq 查询被翻译成 sql 并且它不能包含方法调用。但是您的方法很简单,您可以在查询中内联逻辑

a.AddressLine1 ?? "value"

是的,它不完全一样,但你明白了。

这样做,

var adrsQuery = this.Context.Addresses
    .Where(a => myList.Contains(a.Address_K))
    .ToList() // This line executes the IQueryable and returns an IEnumerable.
    .Select(a => new AlternateAddressesDB
        {
            Line1 = GetAddressLine1(a.AddressLine1),
            Line2 = a.AddressLine2,
            City = a.City,
            State = a.State,
            ZipCode = a.ZipCode
        }).ToList();


    private static string GetAddressLine1(string adrs)
    {
        if (string.IsNullOrWhiteSpace(adrs))
            adrs = "Medical Office";

        return adrs;
    }

where 子句将在服务器端执行,这很好,您不会 return 不需要的数据。使用非数据库函数的转换将在本地完成。

其他人已经向您解释了问题。您无法在 SQL 服务器上执行 C# 方法...

通常您尝试更改您的查询:

var adrsQuery = (from a in this.Context.Addresses
        where myList.Contains(a.Address_K)
        select new AlternateAddressesDB()
        {
            Line1 = a.AddressLine1 == null || a.AddressLine1.TrimEnd() == string.Empty ? "Medical Office" : a.AddressLine1,
            Line2 = a.AddressLine2,
            City = a.City,
            State = a.State,
            ZipCode = a.ZipCode
        }).ToList();

或者您强制在本地执行您的方法:

var adrsQuery = (from a in this.Context.Addresses
        where myList.Contains(a.Address_K)
        select new AlternateAddressesDB()
        {
            Line1 = a.AddressLine1,
            Line2 = a.AddressLine2,
            City = a.City,
            State = a.State,
            ZipCode = a.ZipCode
        })

        .AsEnumerable() // From here the query is executed "locally"

        .Select(a => new AlternateAddressesDB()
        {
            Line1 = GetAddressLine1(a.Line1),
            a.Line2,
            a.City,
            a.State,
            a.ZipCode
        })
        .ToList();

您从数据库加载所需的数据,然后在本地使用这些数据创建一组新对象"manipulated"

(这第二种解决方案通常只在最后的 .Select() 中可用,因为如果你在本地执行完整的 .Where(),你向服务器请求了太多的行,然后你跳过其中许多)

有一个second/third选项: 几天前他们问我如何解决类似的问题。查看我在解决方案中给出的示例。限制是您需要能够将您的方法转换为可以由 Entity Framework 执行的命令(因此您需要将 .IsNullOrWhiteSpace() 转换为可以发送给 SQL 的命令), 比如:

[Expandable]
static string GetAddressLine1(Address address)
{
    // Not necessary to implement, see linked answer
    throw new NotImplementedException();
}

static Expression<Func<Address, string>> GetAddressLine1Expression()
{
    return x => x.AddressLine1 == null || x.AddressLine1.TrimEnd() == string.Empty ? "Medical Office" : x.AddressLine1;
}

请注意,这条路要复杂得多,我不建议胆小的人或那些可以走更容易的路的人(我个人不使用它)