EntityFramework 核心延迟加载 returns 所有相关表

EntityFramework Core Lazy Loading returns all related tables

我的数据库中有 3 个表: 国家 状态 城市

我有一个 API 应该 return 一个国家及其州。

但是,当我尝试这样做时,我最终得到一个 JSON 对象,其中包含国家、统计数据以及每个州下的所有城市

我的代码是这样的(Eager 和 Lazy return 相同):

//Eager Loading
var countries = await _context.Countries.Include(s=>s.States).ToListAsync(cancellationToken);

//Lazy Loading
var countries = await _context.Countries.ToListAsync(cancellationToken);

如何只加载州而离开城市?

我的建议是永远不要 return 个实体。只要实体的 DbContext 作为数据模型的表示,实体就应该存在。视图或 API 使用的模型有不同的用途,应该是 EF 可以填充的简单、可序列化的 POCO。这让它们只适合您 view/consumer 关注的数据。在您的情况下,您只关心国家和州,而不关心城市或其他相关位。您甚至可能不需要关于一个国家或州的所有数据。让 EF 仅针对所需数据构建查询。这提高了查询的性能,减少了服务器和客户端的内存使用,并避免了序列化的陷阱。 (即循环引用)实体应始终代表实体的完整状态。关闭延迟加载和传递不完整的实体图很容易导致错误,因为接受实体引用并面对 null/empty 引用的方法将不知道该引用是未加载还是不存在的区别.

[Serializable]
public class CountryViewModel
{
    public int CountryID { get; set; }
    public string CountryName { get; set; }
    public IEnumerable<StateViewModel> States { get; set; } = new List<StateViewModel>();
}

[Serializable]
public class StateViewModel
{
    public int StateID { get; set; }
    public string StateName { get; set; }
}

然后在获取国家和州时:

var countries = await _context.Countries
    .Select(x => new CountryViewModel
    {
        CountryId = x.CountryId,
        CountryName = x.Name,
        States = x.States.Select(s => new StateViewModel
        {
            StateId = s.StateId,
            StateName = s.Name
        }).ToList()
    }).ToListAsync(cancellationToken);

利用 Automapper,这可以很容易地简化为:

var countries = await _context.Countries
    .ProjectTo<CountryViewModel>()
    .ToListAsync(cancellationToken);