在 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;
}
请注意,这条路要复杂得多,我不建议胆小的人或那些可以走更容易的路的人(我个人不使用它)
我有这样的东西:
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选项:.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;
}
请注意,这条路要复杂得多,我不建议胆小的人或那些可以走更容易的路的人(我个人不使用它)