如何仅使用数据库中的Entity Framework Scaffolded Models

Jos*_*ero 1 c# entity-framework-core .net-core asp.net-core

我一直在使用.Net Core Entity Framework数据库第一种方法和Scaffolding技术.

它从我的数据库表中生成了几个模型/类,但是现在,我将最小化我对这两个表的问题...在两个ChampionID列上的一对多关系:

在此输入图像描述

因此,在使用EntityCore Tools对模型进行脚手架/映射之后,它会生成以下两个类(以及其他几个不相关的类):

Champion.cs:

public partial class Champion
{
    public Champion()
    {
        ChampionScreenshot = new HashSet<ChampionScreenshot>();
        ChampionUser = new HashSet<ChampionUser>();
        ChampionUserRate = new HashSet<ChampionUserRate>();
    }

    public int ChampionId { get; set; }
    public string Name { get; set; }
    public string Nickname { get; set; }
    public string Description { get; set; }
    public string ImagePath { get; set; }
    public byte AttackDamageScore { get; set; }
    public byte AbilityPowerScore { get; set; }
    public byte ResistanceScore { get; set; }
    public byte PlayingDifficult { get; set; }
    public int PrimaryClassId { get; set; }
    public int SecondaryClassId { get; set; }

    public ChampionClass PrimaryClass { get; set; }
    public ChampionClass SecondaryClass { get; set; }
    public ICollection<ChampionScreenshot> ChampionScreenshot { get; set; }
    public ICollection<ChampionUser> ChampionUser { get; set; }
    public ICollection<ChampionUserRate> ChampionUserRate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

ChampionScreenshot.cs:

public partial class ChampionScreenshot
{
    public int ChampionScreenshotId { get; set; }
    public string ImagePath { get; set; }
    public int ChampionId { get; set; }

    public Champion Champion { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的疑问是:在ChampionScreenshot属性填充的情况下检索Champion对象的正确方法是什么?

例如,这就是我在服务层中所做的事情:

    public async Task<Champion> GetChampion(int id)
    {
        Champion champion = await _context.Champion.FirstAsync(m => m.ChampionId == id);
        champion.ChampionScreenshot = _context.ChampionScreenshot.ToListAsync().Result.FindAll(m => m.ChampionId == champion.ChampionId);

        return champion;
    } 
Run Code Online (Sandbox Code Playgroud)

所以我基本上得到一个特定的冠军,然后分别填充ChampionScreenshot属性(也是一个类),但问题是我的ChampionScreenshot内部还有一个Champion类属性,它再次完全加载:

在此输入图像描述

一旦它在Restful Service的端点中暴露,这显然会产生错误:

[Produces("application/json")]
[Route("api/Champions")]
public class ChampionsController : Controller
{
    [HttpGet("{id}")]
    public async Task<IActionResult> GetChampion([FromRoute] int id)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var champion = await _service.GetChampion(id);

        if (champion == null)
        {
            return NotFound();
        }
        return Ok(champion);
    }
    ...
Run Code Online (Sandbox Code Playgroud)

错误:

Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'champion' with type 'ChampionsService.Models.Champion'. Path 'championScreenshot[0]'. 
Run Code Online (Sandbox Code Playgroud)

所以,我正在考虑创建我的自定义模型并用从我的DbContext中提取的数据填充它而不是返回已经创建的模型但我真的认为应该有一种方法来完全只使用映射的模型,我想知道...

SO *_*ood 5

Champion 引用本身:

冠军>多个ChampionScreenshot>冠军(回到原始对象)

这很容易解决:

return Json(champion, new JsonSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Run Code Online (Sandbox Code Playgroud)

或者您可以为整个应用程序执行此操作:

services.AddMvc().AddJsonOptions(opts => 
{
    opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
Run Code Online (Sandbox Code Playgroud)

然后就是:

return Json(champion);
Run Code Online (Sandbox Code Playgroud)

但以下麻烦我:

Champion champion = await _context.Champion.FirstAsync(m => m.ChampionId == id);
champion.ChampionScreenshot = _context.ChampionScreenshot.ToListAsync().Result.FindAll(m => m.ChampionId == champion.ChampionId);
Run Code Online (Sandbox Code Playgroud)

你说的是"去数据库,下载每一个冠军画面,并通过内存搜索找到我想要的那些".这不仅非常慢,而且还浪费了应用程序和数据库中的大量资源.要包含数据,请使用Include:

Champion champion = await _context.Champion
    .Include(x => x.ChampionScreenshot)
    .FirstAsync(x => x.ChampionId == id);
Run Code Online (Sandbox Code Playgroud)

(这说"去数据库并带给我冠军,但也包括所有通过内部联接对应的ChampionScreenshot).