ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

如何从具有多对多关系的C#Web API Visual Studio 2017 RTM提供(GET)复杂(嵌套)JSON?

2019-07-06 00:05:20  阅读:146  来源: 互联网

标签:json c asp-net-web-api ef-code-first get


我很久以来一直坚持这个问题.

我的环境:

> Visual Studio 2017 RTM(使用此IDE的默认.net核心版本)
> Web API
> ASP.NET核心1.1
> MySQL通过Pomelo数据库提供商

我安装的包:

Microsoft.EntityFrameworkCore
Pomelo.EntityFrameworkCore.MySql 
Microsoft.EntityFrameworkCore.Tools

我首先使用代码创建了3个表.

>员工:有员工名单
>申请:申请表
> EmployeeApplications:Employees和Applications的Join表

Employee和Application具有M:M关系,因此我在它们之间创建了连接表.

员工模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace Test.Models
{
    public class Employee
    {
        public int EmployeeId { get; set; }

        [Required]
        public string LName { get; set; }

        [Required]
        public string FName { get; set; }

        public string Title { get; set; }

        //Navigation Property
        public ICollection<EmployeeApplications> EmployeeApplications { get; set; }
    }
}

应用模型:

using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace Teset.Models
{
    public class Application
    {
        public int ApplicationId { get; set; }

        [Required]
        public string Name { get; set; }

        public string Description { get; set; }

        //Navigation Property
        public ICollection<EmployeeApplications> EmployeeApplications { get; set; }
    }
}

员工应用模型:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Test.Models
{
    public class EmployeeApplications
    {
        public int EmployeeId { get; set; }
        public int ApplicationId { get; set; }
        public Employee Employee { get; set; }
        public Application Application { get; set; }
    }
}

员工控制员:

[Produces("application/json")]
[Route("api/Employees")]
public class EmployeesController : Controller
{
    private readonly TestContext _context;

    public EmployeesController(TestContext context)
    {
        _context = context;
    }

    // GET: api/Employees
    [HttpGet]
    public IEnumerable<Employee> GetEmployees()
    {
        return _context.Employees;
    }

语境:

using Test.Models;
using Microsoft.EntityFrameworkCore;

namespace Test.Data
{
    public class TestContext : DbContext
    {
        public TestContext(DbContextOptions<TestContext> options) : base(options)
        {
        }

        public DbSet<Employee> Employees { get; set; }
        public DbSet<Application> Applications { get; set; }
        public DbSet<EmployeeApplications> EmployeeApplications { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<EmployeeApplications>()
                .HasKey(c => new { c.EmployeeId, c.ApplicationId });
        }
    }
}

我尝试过使用.Include().当我跑去api / Employees时,我得到Postman的“无法得到任何回应”.

return _context.Employees.Include(e => e.EmployeeApplications);

我已经尝试了很多变化,但仍然没有运气.包含.Include()的任何变体都会失败.

电流输出样本:

[{
    "employeeId": 1,
    "lName": "Doe",
    "fName": "John",
    "title": "Senior Software Engineer",
    "employeeApplications": null
},
{
    "employeeId": 2,
    "lName": "Smith",
    "fName": "Jack",
    "title": "Project Manager",
    "employeeApplications": null
}]

我尝试使用DTO并取得了一些成功.我设法用employeeApplications中的内容替换上面的null,但是后来对Employee和Applications有了null引用.

我理想的输出:

[{
    "employeeId": 1,
    "lName": "Doe",
    "fName": "John",
    "title": "Senior Software Engineer",
    "employeeApplications": [{
        "applicationId": 1,
        "name": "Application 1",
        "description": "Description 1",
    },
    {
        "applicationId": 2,
        "name": "Application 2",
        "description": "Description 2",
    }]
},
{
    "employeeId": 2,
    "lName": "Smith",
    "fName": "Jack",
    "title": "Project Manager",
    "employeeApplications": [{
        "applicationId": 2,
        "name": "Application 2",
        "description": "Description 2",
    },
    {
        "applicationId": 3,
        "name": "Application 3",
        "description": "Description 3",
    }]
}]

基本上我想提供一份“员工”列表和他们所使用的应用程序.稍后我还要提供一份应用程序列表和处理它们的员工.

编辑:上面添加了上下文文件

编辑2:我遵循Bchir Med Amine的解决方案(目前没有工作),但后来我添加到Startup.cs的ConfigureServices方法:

services.AddMvc()
                .AddJsonOptions(
                    options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
                );

这让我获得了有关我的JSON的更多信息,但仍未完整. JSON现在看起来像这样:

[{
    "employeeId": 1,
    "lName": "Doe",
    "fName": "John",
    "title": "Senior Software Engineer",
    "employeeApplications": [{
        "employeeId": 1,
        "applicationId": 1,
        "application": null
    },
    {
        "employeeId": 1,
        "applicationId": 2,
        "application": null
    }]
},
{
    "employeeId": 2,
    "lName": "Smith",
    "fName": "Jack",
    "title": "Project Manager",
    "employeeApplications": [{
        "employeeId": 2,
        "applicationId": 2,
        "application": null
    },
    {
        "employeeId": 2,
        "applicationId": 3,
        "application": null
    }]
}]

应用程序现在为null.我不得不使用.Include()来生成它,但是在包含应用程序之后使用.ThenInclude()不起作用.理想的情况是打印出所有员工的清单,每个员工都应该有一份申请清单.

编辑3:我错了.ThenInclude()没有工作,是Intelisense让我失望.如果我使用.ThenInclud()我得到这个JSON:

[{
    "employeeId": 1,
    "lName": "Doe",
    "fName": "John",
    "title": "Senior Software Engineer",
    "employeeApplications": [{
        "employeeId": 1,
        "applicationId": 1,
        "application": {
            "applicationId": 1,
            "name": "Application 1",
            "description": "Description 1",
            "employeeApplications": []
        }
    },
    {
        "employeeId": 1,
        "applicationId": 2,
        "application": {
            "applicationId": 2,
            "name": "Application 2",
            "description": "Description 2",
            "employeeApplications": []
        }
    }]
},
{
    "employeeId": 2,
    "lName": "Smith",
    "fName": "Jack",
    "title": "Project Manager",
    "employeeApplications": [{
        "employeeId": 2,
        "applicationId": 2,
        "application": {
            "applicationId": 2,
            "name": "Application 2",
            "description": "Description 2",
            "employeeApplications": [{
                "employeeId": 1,
                "applicationId": 2,
                "employee": {
                    "employeeId": 1,
                    "lName": "Doe",
                    "fName": "John",
                    "title": "Senior Software Engineer",
                    "employeeApplications": [{
                        "employeeId": 1,
                        "applicationId": 1,
                        "application": {
                            "applicationId": 1,
                            "name": "Application 1",
                            "description": "Description 1",
                            "employeeApplications": []
                        }
                    }]
                }
            }]
        }
    },
    {
        "employeeId": 2,
        "applicationId": 3,
        "application": {
            "applicationId": 3,
            "name": "Application 3",
            "description": "Description 3",
            "employeeApplications": []
        }
    }]
}]

第一个员工对象是Ok(仍然不理想,但它可以工作),但第二个员工不是.第二个打印出员工的应用程序,然后打印出这些应用程序的员工.

编辑4:以下是我返回JSON的方式:

return _context.Employees; //Returns just employees and '[]' for employeeApplications
return _context.Employees.Include(e => e.EmployeeApplications); //returns employees and their employeeApplications, but the applications of employeeApplications is empty
return _context.Employees.Include(e => e.EmployeeApplications).ThenInclude(ea => ea.Application); //returns everything, but continues due to circular reference

解决方法:

也许你必须将Virtual添加到类中

public class Application
{
    #region Public Constructors

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Application()
    {
        EmployeeApplications = new HashSet<EmployeeApplications>();
    }

    #endregion Public Constructors

    #region Public Properties

    public int ApplicationId { get; set; }

    public string Description { get; set; }

    //Navigation Property
    public virtual ICollection<EmployeeApplications> EmployeeApplications { get; set; }

    [Required]
    public string Name { get; set; }

    #endregion Public Properties
}

public class Employee
{
    #region Public Constructors

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Employee()
    {
        EmployeeApplications = new HashSet<EmployeeApplications>();
    }

    #endregion Public Constructors

    #region Public Properties

    //Navigation Property
    public virtual ICollection<EmployeeApplications> EmployeeApplications { get; set; }

    public int EmployeeId { get; set; }

    [Required]
    public string FName { get; set; }

    [Required]
    public string LName { get; set; }

    public string Title { get; set; }

    #endregion Public Properties
}

public class EmployeeApplications
{
    #region Public Properties

    public virtual Application Application { get; set; }
    public int ApplicationId { get; set; }
    public virtual Employee Employee { get; set; }
    public int EmployeeId { get; set; }

    #endregion Public Properties
}

标签:json,c,asp-net-web-api,ef-code-first,get
来源: https://codeday.me/bug/20190705/1392011.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有