简体   繁体   English

Ef core 6 尝试使用时抛出错误 500.ThenInclude 方法

[英]Ef core 6 throws error 500 when trying to use .ThenInclude method

I have two tables Employee and Skill which are connected using many to many relationship with the EmployeeSkill association class.我有两个表 Employee 和 Skill,它们使用与 EmployeeSkill 关联 class 的多对多关系连接。 The query bellow works properly however: 1] When I call employees method I get the correct amount of Counted Skill referenced objects but they are all initialized as zeros and 2] When I try to add ThenInclude query it throws 500 error.但是,下面的查询可以正常工作:1] 当我调用 employees 方法时,我得到了正确数量的 Counted Skill 引用对象,但它们都被初始化为零,2] 当我尝试添加 ThenInclude 查询时,它会抛出 500 错误。

Thank you very much for your time非常感谢您的宝贵时间

Edit: One solution was to add to Startup.cs the following line of code:编辑:一种解决方案是向 Startup.cs 添加以下代码行:

services.AddControllers().AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);

Server Exception:服务器异常:

An unhandled exception has occurred while executing the request.执行请求时发生未处理的异常。 System.Text.Json.JsonException: A possible object cycle was detected. System.Text.Json.JsonException:检测到可能的 object 循环。 This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32这可能是由于循环或 object 深度大于最大允许深度 32

Client Exception:客户端异常:

Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Response status code does not indicate success: 500 (Internal Server Error).
System.Net.Http.HttpRequestException: Response status code does not indicate success: 500 (Internal Server Error).
   at System.Net.Http.HttpResponseMessage.EnsureSuccessStatusCode()
   at System.Net.Http.HttpClient.GetStreamAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
   at SkillMatrix.Client.Services.EmployeeDataService.GetEmployeesAsync() in C:\Users\Onelity-mefraimidis\Downloads\Onelity related\.NET projects\SkillMatrix\SkillMatrix.Client\Services\EmployeeDataService.cs:line 30
   at SkillMatrix.Client.Features.EmployeeView.EmployeeOverviewPage.OnInitializedAsync() in C:\Users\Onelity-mefraimidis\Downloads\Onelity related\.NET projects\SkillMatrix\SkillMatrix.Client\Features\EmployeeView\EmployeeOverviewPage.cs:line 54
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
   at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)

Context (is added correctly in the sql database):上下文(在 sql 数据库中正确添加):

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // Configure a Many-to-Many Relationship using Fluent API   
    modelBuilder.Entity<Employee>()
                .HasMany(e => e.Skills)
                .WithMany(s => s.Employees)
                .UsingEntity<EmployeeSkill>(
        j => j.HasOne(m => m.Skill).WithMany(g => g.EmployeeSkills),
        j => j.HasOne(m => m.Employee).WithMany(g => g.EmployeeSkills),
        je =>
        {
            je.HasKey("EmployeesId", "SkillsId");
            je.HasData(
                new EmployeeSkill { EmployeesId = 1, SkillsId = 1 },
                new EmployeeSkill { EmployeesId = 1, SkillsId = 3 },
                new EmployeeSkill { EmployeesId = 1, SkillsId = 4 },
                new EmployeeSkill { EmployeesId = 1, SkillsId = 5 },
                new EmployeeSkill { EmployeesId = 1, SkillsId = 8 },

                new EmployeeSkill { EmployeesId = 2, SkillsId = 1 },
                new EmployeeSkill { EmployeesId = 2, SkillsId = 2 },
                new EmployeeSkill { EmployeesId = 2, SkillsId = 3 },
                new EmployeeSkill { EmployeesId = 2, SkillsId = 11 },
                new EmployeeSkill { EmployeesId = 2, SkillsId = 15 },

                new EmployeeSkill { EmployeesId = 3, SkillsId = 10 },
                new EmployeeSkill { EmployeesId = 3, SkillsId = 22 },
                new EmployeeSkill { EmployeesId = 3, SkillsId = 23 },
                new EmployeeSkill { EmployeesId = 3, SkillsId = 40 },
                new EmployeeSkill { EmployeesId = 3, SkillsId = 47 }
                );
        }
        );

Classes:课程:

public class EmployeeSkill
{
    public int SkillsId;
    public int EmployeesId;

    public Employee Employee;
    public Skill Skill;
}

public class Employee
{
    public int Id { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "First name is too long.")]
    public string FirstName { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "Last name is too long.")]
    public string LastName { get; set; }

    public DateTime DateOfBirth { get; set; }

    [Required]
    [EmailAddress]
    public string Email { get; set; }

    [Required]
    [Phone]
    public string PhoneNumber { get; set; }

    public bool Smoker { get; set; }

    public MaritalStatus MaritalStatus { get; set; }

    public Gender Gender { get; set; }

    [StringLength(1000, ErrorMessage = "Comment length cannot exceed 1000 characters.")]
    public string Comment { get; set; }

    public DateTime? JoinedDate { get; set; }

    public DateTime? LastUpdateDate { get; set; }

    public DateTime? ExitDate { get; set; }

    public int JobCategoryId { get; set; }

    public JobCategory JobCategory { get; set; }

    #region Navigation Properties
    public virtual EmployeeAddress Address { get; set; }

    public virtual ICollection<Skill> Skills { get; set; }
    public virtual ICollection<EmployeeSkill> EmployeeSkills { get; set; }

    #endregion
}

public class Skill
{
    public int Id { get; set; }

    [Required]
    [StringLength(50, ErrorMessage = "Name is too long.")]
    public string Name { get; set; }

    public string Description { get; set; }

    public Level Level { get; set; }

    public int SkillCategoryId { get; set; }

    #region Navigation Properties
    public virtual SkillCategory SkillCategory { get; set; }

    public virtual ICollection<Employee> Employees { get; set; }
    public virtual ICollection<EmployeeSkill> EmployeeSkills { get; set; }

    #endregion
}

Service method:服务方式:

public async Task<IEnumerable<EmployeeSkillResponse>> GetEmployeeSkillsAsync()
{
    return await JsonSerializer.DeserializeAsync<IEnumerable<EmployeeSkillResponse>>(await _httpClient.GetStreamAsync("api/employeeskills"),
                                    new JsonSerializerOptions() { PropertyNameCaseInsensitive = true });
}

Repository:存储库:

public IEnumerable<Employee> GetEmployees()
{
    var query1 = _skillMatrixContext.Employees.Include(employee => employee.EmployeeSkills).ToList();

    // initially was query
    //var query = _skillMatrixContext.Employees;

    // this throws 500 error
    //var query2 = _skillMatrixContext.Employees.Include(employee => employee.EmployeeSkills).ThenInclude(skill=>skill.Skill).ToList();
    
    return query1;
}

Controller method: Controller 方法:

[HttpGet]
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IEnumerable<EmployeeResponse>))]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Produces(MediaTypeNames.Application.Json)]
public ActionResult<IEnumerable<EmployeeResponse>> GetEmployees()
{
    var employeesFromRepo = _employeeRepository.GetEmployees();

    return Ok(_mapper.Map<IEnumerable<EmployeeResponse>>(employeesFromRepo));
}

One solution was to add to Startup.cs the following line of code:一种解决方案是向 Startup.cs 添加以下代码行:

services.AddControllers().AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);

Also it must be noted that AsNoTracking() can be used in the end of the query.还必须注意 AsNoTracking() 可以在查询结束时使用。 Quoting Svyatoslav Danyliv: EF Core fixup navigation properties via ChangeTracker and it may cause circular reference in loaded objects - that's why you have exception.引用 Svyatoslav Danyliv: EF Core fixup navigation properties via ChangeTracker,它可能会导致加载对象中的循环引用——这就是你有异常的原因。 AsNoTracking() disables this fixup and change tracking which may speedup loading records. AsNoTracking() 禁用此修复和更改跟踪,这可能会加速加载记录。 Usually when right API is written, it uses DTO classes for returning information via network and such problem almost never appear通常在写API的时候,它使用DTO类通过网络返回信息,这样的问题几乎不会出现

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM