在LINQ中调用方法

时间:2015-03-20 14:40:00

标签: c# linq linq-to-entities

我有这样的事情:

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), 看起来我不能在那里调用一个方法,我怎么能在方法中执行这个逻辑而不用那样调用它?

4 个答案:

答案 0 :(得分:4)

问题不在于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;
}

答案 1 :(得分:4)

其他人已经向您解释了这个问题。您无法在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();

您从数据库加载您需要的数据,然后在本地创建一组新的对象,数据“被操纵”

(这个第二个解决方案通常只能在最后的.Select()中使用,因为如果你在本地执行一个完整的.Where(),你要求服务器有太多行,然后你跳过很多他们)

还有第二个/第三个选项:https://stackoverflow.com/a/29128874/613130 几天前他们问我如何解决类似的问题。看看我给出的解决方案示例。限制是您需要能够将方法转换为可由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;
}

请注意,这条道路要复杂得多,我不建议那些胆小的人,或者那些可以追随更轻松道路的人(我个人不会使用它)

答案 2 :(得分:3)

这样做,

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子句将在服务器端执行,这是好的,你不会返回不必要的数据。使用非数据库函数的转换将在本地完成。

答案 3 :(得分:2)

我认为这个问题的关键是this.Context,我认为这是一些问题。所以你的linq查询被转换为sql,它不能包含方法调用。但是你的方法很简单,你可以在查询中内联逻辑

a.AddressLine1 ?? "value"

是的,它不完全相同,但你明白了。