One To Many returns empty array (solved)

爷,独闯天下 提交于 2020-06-07 05:49:45

问题


I'm trying to connect two objects with one-to-many relationship, Workplace can hold multiple People, while one Person can only have one Workplace.

When I execute this code snippet and check to see the results, p1 has properly assigned w1 as the p1.Workplace, but the list of people of the w1.employees is always empty.

Do I have to manually add p1 to w1.Employees even after I assigned w1 to p1.Workplace?

SeedData.cs (code snippet)

var w1 = new Workplace
{
   EntryCode = "1111"
   //[...] other data I cut out for brievity
};
context.Workplaces.Add(w1);

Person p1 = new Person
{
    Name = "Spencer",
    Workplace = w1
   //[...] other data I cut out for brievity
};
context.Person.Add(p1)
context.SaveChanges();

Workplace.cs

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace Counsel.Models
{
    [Table("Workplace")]
    public class Workplace
    {
        [Column("WorkplaceId")]
        public int WorkplaceId {get;set;}

        [Column("EntryCode")]
        public string EntryCode {get;set;}

        [Column("ConfirmationCode")]
        public string ConfirmationCode {get;set;}

        [Column("Employees")]
        public ICollection<Person> Employees {get;set;}
    }
}

Person.cs

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace Counsel.Models
{
    public class Person
    {
        [Column("PersonId")]
        public int PersonId {get;set;}

        [Column("Image")]
        public string Image {get;set;}

        [Column("FName")]
        public string FName { get; set; }

        [Column("LName")]
        public string LName {get;set;}

        [Column("Role")]
        public string Role {get;set;}

        [Column("Email")]
        public string Email {get;set;}

        [Column("Password")]
        public string Password {get;set;}

        public Workplace Workplace {get;set;} = new Workplace();
        public ICollection<ChatPerson> Chats {get;set;}
    }
}

DataContext.cs

using Counsel.Models;
using Microsoft.EntityFrameworkCore;

namespace Counsel.Models {
    public class DataContext : DbContext
    {
        public DataContext(DbContextOptions<DataContext> opts): base(opts){}

        public DbSet<Person> People {get;set;}
        public DbSet<Workplace> Workplaces {get;set;}


        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {

            modelBuilder.Entity<Person>((item)=>{
                item.HasKey(p => p.PersonId);
                item.HasOne<Workplace>(p => p.Workplace).WithMany(w => w.Employees).OnDelete(DeleteBehavior.SetNull);
            });


            modelBuilder.Entity<Workplace>((item)=>{
                item.HasKey(p => p.WorkplaceId);
                item.HasMany<Person>(w => w.Employees).WithOne(p => p.Workplace).OnDelete(DeleteBehavior.Cascade);
            });
        }
    }
}

WorkplaceController.cs (code snippet)

[HttpGet("{id}")]
        public Workplace GetWorkplace(int id)
        {
           return context.Workplaces
                .Where(c => c.WorkplaceId == id)
                .Include(c => c.Employees).ThenInclude(c => c.Workplace)
                .FirstOrDefault();

        }

GetWorplace() output

[
  {
    "workplaceId": 1,
    "entryCode": "1111",
    "confirmationCode": "1111",
    "employees": [

    ]
  }
]

As you can see, the "employees" array is empty, even though p1 should be there.


回答1:


The problem is caused by the reference navigation property initializer:

public Workplace Workplace { get; set; } = new Workplace(); // <--

Never do that - it confuses EF navigation property fixup and leads to unexpected runtime behaviors.

Note that initializing collection navigation properties is ok, although not required. It's because null in reference navigation property have a special meaning and really provides a link to the principal entity, which may or may not contain collection of dependent entities.

Shortly, remove the initializer

public Workplace Workplace { get; set; }

and the issue will be solved.




回答2:


If you are using lazy loading of the data you need to enumerate the data in order for them to be pulled into the EF context. Child elements are not retrieved by default. Another thing you can do is explicitly include the children when constructing the query. You can see how the include operation works here: https://entityframework.net/include-multiple-levels

And you can also see the related issue here: Include children in EF




回答3:


Workplace has a relationship property Employees, but it is mapped [Column("Employees")] which I'm guessing causes EF to stop treating it as a relationship to find the other entities through, and starts treating it as a column that exists in the Workplace table. Remove the column attribute and, if necessary, provide more information to EF so that it can properly map the Person * ↔ 1 Workplace relationship.



来源:https://stackoverflow.com/questions/60488594/one-to-many-returns-empty-array-solved

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!