[英]Entity Framework Core: many-to-many relationship with the same object
[英]Entity Framework Core returning object with many to many relationship
我不确定如何将EF Core与.NET Core应用程序结合使用来获取所需的信息。 我有两个数据库表-具有多对多关系的OBJECTS和TAGS(使用第三个联接表OBJECTTAGS)。 我想获取所有对象(大约1400个)及其关联的标签。
这是我的三个模型:
using System;
using System.Collections.Generic;
namespace ContentMarketplace.Models
{
public partial class Object
{
public int ObjectId { get; set; }
...
public virtual List<ObjectTag> ObjectTags { get; set; }
}
}
namespace ContentMarketplace.Models
{
public partial class Tag
{
public int TagId { get; set; }
...
public virtual List<ObjectTag> ObjectTags { get; set; }
}
}
namespace ContentMarketplace.Models
{
public partial class ObjectTag
{
public int ObjectId { get; set; }
public virtual Object Object { get; set; }
public int TagId { get; set; }
public virtual Tag Tag { get; set; }
}
}
这就是我上下文中的OnModelCreating()方法中的内容:
modelBuilder.Entity<ObjectTag>(entity =>
{
entity.HasKey(e => new { e.ObjectId, e.TagId });
entity.HasOne(ot => ot.Object)
.WithMany(o => o.ObjectTags)
.HasForeignKey(ot => ot.ObjectId);
entity.HasOne(ot => ot.Tag)
.WithMany(t => t.ObjectTags)
.HasForeignKey(ot => ot.TagId);
});
当我尝试在ObjectController.cs中返回数据时,会出现此问题
namespace ContentMarketplace.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ObjectController : ControllerBase
{
private readonly ContentMarketplaceContext _context;
public ObjectController(ContentMarketplaceContext context)
{
_context = context;
}
[HttpGet]
public ActionResult<List<ContentMarketplace.Models.Object>> GetAll()
{
return _context.Objects
.Include(o => o.ObjectTags)
.ThenInclude(ot => ot.Tag)
.ToList();
}
}
}
Include()。ThenInclude()创建一个循环关系,其中HTTP请求不仅返回与每个对象关联的标签信息,而且还返回与每个标签关联的所有对象,依此类推,从而使浏览器崩溃。
如果我取出ThenInclude()可以正常工作,但不会返回不在我的ObjectTag模型中的所有标签信息。
我知道这与上下文中已经存在的EF Core自动加载有关(例如此处的“技巧”说明https://docs.microsoft.com/zh-cn/ef/core/querying/related-data ),但是我不知道该如何进一步返回对象和标签。
您的问题是由循环引用引起的,您可以尝试在下面忽略循环引用。
services.AddMvc()
.AddJsonOptions(opt => {
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
对于另一个选项,您可以尝试直接使用List<Tag>
而不是List<ObjectTag>
返回ObjectModel
。
ObjectModel
public partial class ObjectModel
{
public int ObjectId { get; set; }
public string Name { get; set; }
public virtual List<Tag> Tags { get; set; }
}
询问
public List<Models.ObjectModel> GetAll()
{
//return _db.Object
// .Include(o => o.ObjectTags)
// .ThenInclude(ot => ot.Tag)
// .ToList();
return _db.Object
.Include(o => o.ObjectTags)
.ThenInclude(ot => ot.Tag)
.Select(r => new Models.ObjectModel
{
ObjectId = r.ObjectId,
Name = r.Name,
Tags = r.ObjectTags.Select(ot => ot.Tag).ToList()
})
.ToList();
}
如果在查询中使用“ Include
或“ Theninclude
Include
,它将创建循环引用。 JSON无法处理循环引用。 您可以使用Select
查询轻松解决此问题。
没有DTO:
编写您的GetAll()
控制器方法,如下所示:
[HttpGet]
public IActionResult GetAll()
{
var objectList = _context.Objects.Select(o => new
{
o.ObjectId,
Tags = o.ObjectTags.Select(ot => ot.Tag).ToList()
}).ToList();
return Ok(objectList);
}
使用DTO:
编写您的DTO类,如下所示:
public class ObjectDto
{
public int ObjectId { get; set; }
....
public List<Tag> Tags { get; set; }
}
然后,您的GetAll()
控制器方法应如下所示:
[HttpGet]
public ActionResult<List<ObjectDto>> GetAll()
{
var objectList = _context.Objects.Select(o => new ObjectDto
{
ObjectId = o.ObjectId,
Tags = o.ObjectTags.Select(ot => ot.Tag).ToList()
}).ToList();
return objectList;
}
注意:如果在查询中使用Select
,则不需要使用Include
或Theninclude
。
希望它现在能按预期工作!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.