[英]How to work only with the Entity Framework Scaffolded Models from Database
I have been working with .Net Core Entity Framework database first approach with the Scaffolding technique. 我一直在使用带有脚手架技术的.Net Core Entity Framework数据库第一种方法。
It generated me a couple Models/Classes from my Database Tables, but for now, I will just minimize the issue I am having to this two tables... a relation one to many on the both ChampionID column: 它从数据库表中生成了几个模型/类,但是现在,我将这两个表的问题减至最少...两个ChampionID列上的一对多关系:
So, after scaffolding/mapping the models with EntityCore Tools it generated the following two classes (and several others that are not relevant): 因此,在使用EntityCore Tools脚手架/映射模型之后,它生成了以下两个类(以及其他几个不相关的类):
Champion.cs: 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: 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; }
}
My doubt is: what is the correct way to retrieve a Champion object with the ChampionScreenshot attribute filled? 我的疑问是:检索带有ChampionScreenshot属性填充的Champion对象的正确方法是什么?
For example, this is what I am doing in my Service layer: 例如,这就是我在服务层中所做的事情:
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;
}
So I am basically getting a specific Champion and then filling the ChampionScreenshot attribute (which is also a Class) separately, but the thing is that inside my ChampionScreenshot there is also a Champion class attribute which fully loads once again: 所以我基本上是得到一个特定的Champion,然后分别填充ChampionScreenshot属性(也是Class),但事实是,我的ChampionScreenshot中还有一个Champion类属性,可以再次完全加载:
Which is obviously generating an error once it is exposed in the endpoint of the Restful Service: 一旦将其暴露在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);
}
...
Error: 错误:
Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'champion' with type 'ChampionsService.Models.Champion'. Path 'championScreenshot[0]'.
So, I was thinking in just creating my custom model and fill it with the data extracted from my DbContext instead of returning the models already created but I really think that there should be a way to fully use only the mapped Models, I was wondering that... 因此,我在考虑只创建自定义模型并用从DbContext中提取的数据填充它,而不是返回已经创建的模型,但是我真的认为应该有一种方法可以仅使用映射的模型,我想知道...
Champion
references itself: Champion
称呼自己:
Champion > multiple ChampionScreenshot > Champion (back to the original object) 冠军>多个冠军屏幕截图>冠军(返回原始对象)
That's easy to solve: 这很容易解决:
return Json(champion, new JsonSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
Or you could do it for the entire application: 或者您可以对整个应用程序执行此操作:
services.AddMvc().AddJsonOptions(opts =>
{
opts.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
And then just: 然后:
return Json(champion);
The following troubles me, though: 但是,以下问题困扰着我:
Champion champion = await _context.Champion.FirstAsync(m => m.ChampionId == id);
champion.ChampionScreenshot = _context.ChampionScreenshot.ToListAsync().Result.FindAll(m => m.ChampionId == champion.ChampionId);
You are saying "go to the database, download every single championscreenshot and find the ones I want through an in-memory search". 您说的是“转到数据库,下载每个冠军屏幕快照,然后通过内存搜索找到我想要的屏幕快照”。 That's not only horrible slow, it also wastes a lot of resources in your application and in the database.
这不仅令人震惊,而且还浪费了应用程序和数据库中的大量资源。 For including data, you use
Include
: 要包含数据,请使用
Include
:
Champion champion = await _context.Champion
.Include(x => x.ChampionScreenshot)
.FirstAsync(x => x.ChampionId == id);
(this says "go to the database and bring me the champion but also include all the ChampionScreenshot that correspond, through an inner join). (这表示“进入数据库并带给我冠军,但也通过内部联接包括所有对应的ChampionScreenshot)”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.