Entity Framework Core返回具有多对多关系的对象

问题描述 投票:1回答:2

我不确定如何使用带有.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对象和标签而不再进一步。

c# asp.net-core entity-framework-core
2个回答
0
投票

如果在查询中使用IncludeTheninclude,它将创建循环引用。 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,则不需要使用IncludeTheninclude

希望现在能按预期工作!


0
投票

您的问题是由循环引用引起的,您可以尝试在下面忽略循环引用。

            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();
    }
© www.soinside.com 2019 - 2024. All rights reserved.