查询所有记录,包括相关记录的数量

时间:2019-04-10 14:31:03

标签: c# .net entity-framework-core

在具有Entity Framework Core的ASP.NET Core应用程序中,显示记录列表。因此,将提取集合的所有实体,并将其某些属性显示在表中。

此外,还存在通过外键连接的相关实体。对于其中某些对象,还应该显示对象总数。

例如,有以下表格(简化):

  • 位置(ID,名称,地址)
  • 设备(ID,名称,评论,LocationId)

此处仅显示位置(主要实体)和设备(相关实体),但是除了设备之外还有更多类型。数据库中的所有设备都分配到一个位置。实体类中包含外键和导航属性,以及非映射计数属性(请参见最后一个示例)。

期望的结果是这样

  • 此位置的位置ID 1,名称1, 15 个设备
  • 该位置中的位置ID 2,名称2, 6 个设备
  • 位置ID 3,名称3,此位置中的 0 个设备

我可以先按名称顺序获取位置,然后在单独的数据库查询中获取每个位置的设备数量。这可能会导致大量的简短查询。

var locations = dbContext.Locations
    .OrderBy(l => l.Name)
    .ToList();
foreach (var location in locations)
{
    int count = dbContext.Devices.Where(d => d.LocationId == location.Id).Count();
}

我还可以使用Include(location => location.Devices)来获取所有位置,然后仅使用location.Devices.Count来获取它们的数量,但这涉及到获取所有设备的所有详细信息,最后只使用它们的总数。 / p>

var locations = dbContext.Locations
    .Include(l => l.Devices)
    .OrderBy(l => l.Name)
    .ToList();
foreach (var location in locations)
{
    int count = location.Devices.Count;
}

我可以像往常一样先获取所有位置,然后构建一个查询来收集所有位置的设备计数。然后,我必须通过遍历一个列表并在另一个列表中找到相应的条目来手动合并这些结果集,这可能导致大量的内存搜索。

var locations = dbContext.Locations
    .OrderBy(l => l.Name)
    .ToList();
var deviceCounts = dbContext.Locations
    .Select(l => new
    {
        l.Id,
        l.Devices.Count
    });
foreach (var c in deviceCounts)
{
    locations.First(l => l.Id == c.Id).DeviceCount = c.Count;
}

我正在寻找一个查询,以获取按位置排序的位置(按名称排序)以及每个位置的设备计数。结果必须是我的实体类型的列表,例如List<Location>。是否有一种简单或有效的方法可以通过EF Core实现?

2 个答案:

答案 0 :(得分:1)

首先,创建一个ViewModel类并定义要在列表中显示的属性。 ViewModel将仅提供您需要的数据,而不是整个实体。例如:

public class DeviceViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int DeviceCount { get; set; }
}

然后,执行要返回ViewModel列表的查询,该列表与来自实体的数据混合在一起,该实体定义了您想要的Select方法之前的顺序。

var devices = dbContext.Locations
                       .Include(l => l.Devices)                           
                       .OrderBy(x => x.Name)          
                       .Select(l => new DeviceViewModel()
                       {
                          Id = l.Id,
                          Name = l.Name,
                          DevicesCount = l.Devices.Count()
                       })
                       .ToList();

记住要调用ToList()来强制ORM在数据库上执行查询。

答案 1 :(得分:0)

您需要选择所需的值。

var locations = dbContext.Locations
.Include(l => l.Devices)
.OrderBy(l => l.Name)
.Select( l => new {
             LocationId = l.Id,
             LocationName = l.Name,
             DeviceCount = l.Devices.Count()
        })
.ToList();