Sla*_*uma 2 c# linq linq-to-entities entity-framework
我有一个Address模型(简化)......
public class Address
{
public int AddressId { get; set; }
public string City { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
...以及DbContext包含一组的派生类Addresses:
public DbSet<Address> Addresses { get; set; }
Run Code Online (Sandbox Code Playgroud)
然后我有这个查询应该检索一个或不address(_context是我的数据库上下文类的实例):
public Address GetAddress(string city, int addressId)
{
Address address = null;
// this is a database query
var addresses = _context.Addresses.Where(a => a.City == city).ToList();
// the rest queries in memory
if (addresses.Count <= 1)
address = addresses.FirstOrDefault();
else
{
address = addresses.FirstOrDefault(a => a.AddressId == addressId);
if (address == null)
address = addresses.FirstOrDefault();
}
return address;
}
Run Code Online (Sandbox Code Playgroud)
查询有点奇怪.逻辑很简单:
city将此地址作为结果.city的是具有给定的地址addressId.如果没有结果地址,那么addressId只需要第一个.令人不安的是,.ToList()调用可能会将大量地址加载到我不感兴趣的内存中.最后,我只过滤了内存中加载的一个地址作为最终结果.
有没有办法重写这个查询(使用LINQ到实体),以便它在数据库中完全运行并只返回一个或没有地址(使用单个数据库往返)?
您的逻辑可以被解释为更喜欢具有给定ID的地址,并且如果没有匹配jut pick any.您的查询不会强制执行该案例的任何订单.
var addressesInCity = _context.Addresses.Where(a => a.City == city);
var addrByID = addressesInCity.Where(a => a.AddressId == addressId);
var anyAddr = addressesInCity.Take(1);
Run Code Online (Sandbox Code Playgroud)
你可以用两个查询来写这个:
addrByID.FirstOrDefault() ?? anyAddr.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
您可以将它们组合成一个查询:
addrByID.Select(a => new { Priority = 1, a })
.Concat(anyAddr.Select(a => new { Priority = 2, a }))
.OrderBy(x => x.Priority)
.Take(1)
.Select(x => x.a)
.FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
这样可以节省往返次数,SQL Server可以通过常量来理解排序.它将有效运行.没有一定的效率比第一种形式,但不显著恶化.
请注意,返回的结果顺序UNION (ALL)未定义.我们需要通过引入一个Priority字段来强制执行订单.
| 归档时间: |
|
| 查看次数: |
72 次 |
| 最近记录: |