我不确定如何使用带有.NET Core应用程序的EF 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/en-us/ef/core/querying/related-data中的“提示”注释)但我不知道如何返回JUST对象和标签而不再进一步。
如果在查询中使用Include
或Theninclude
,它将创建循环引用。 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
。
希望现在能按预期工作!
您的问题是由循环引用引起的,您可以尝试在下面忽略循环引用。
services.AddMvc()
.AddJsonOptions(opt => {
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
对于另一种选择,你可以尝试直接用ObjectModel
而不是List<Tag>
返回List<ObjectTag>
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();
}