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

时间:2018-05-21 22:36:24

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

我一直在使用.Net核心实体框架数据库第一种方法和Scaffolding技术。

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

enter image description here

因此,在使用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; }
}

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; }
}

我的疑问是:在填充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;
    } 

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

enter image description here

一旦在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);
    }
    ...

错误:

Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'champion' with type 'ChampionsService.Models.Champion'. Path 'championScreenshot[0]'. 

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

1 个答案:

答案 0 :(得分:5)

Champion引用自己:

冠军&gt;多个ChampionScreenshot&gt;冠军(回到原始对象)

这很容易解决:

return Json(champion, new JsonSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });

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

services.AddMvc().AddJsonOptions(opts => 
{
    opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});

然后只是:

return Json(champion);

但是,我遇到了以下麻烦:

Champion champion = await _context.Champion.FirstAsync(m => m.ChampionId == id);
champion.ChampionScreenshot = _context.ChampionScreenshot.ToListAsync().Result.FindAll(m => m.ChampionId == champion.ChampionId);

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

Champion champion = await _context.Champion
    .Include(x => x.ChampionScreenshot)
    .FirstAsync(x => x.ChampionId == id);

(这表示“进入数据库并为我带来冠军,但也包括所有通过内部联接对应的ChampionScreenshot)。