简体   繁体   English

实体框架中未填充外键

[英]Foreign key not populating in Entity Framework

I cannot get a table to update correctly that should be linking two of my entities.我无法正确更新应该链接我的两个实体的表。 To explain in more detail...I have two entities, Class and Teacher , with a relationship in the form of:更详细地解释......我有两个实体ClassTeacher ,它们的关系为:

  1. Teacher can be assigned to many classes老师可以分配到多个班级
  2. Class can only have one teacher.班级只能有一位老师。

Below are these two entities.下面是这两个实体。

public class Teacher
{
    [Required, Key]
    public Guid Id { get; private set; }
    [StringLength(50)]
    public string Name { get; set; }
    public string Email { get; set; }
    public List<Class> Classes = new List<Class>();

    public Teacher()
    {
        Id = new Guid();
    }

    public Teacher(Guid id)
    {
        Id = id;
    }

    public void AssignClass(Class newClass)
    {
        Classes.Add(newClass);
    }
}

public class Class
{
    [Required, Key]
    public Guid Id { get; private set; }
    [Required, StringLength(20)]
    public string Name { get; set; }
    [Required, Range(5, 30)]
    public int Capacity { get; set; }
    public Teacher Teacher { get; set; }
    public IEnumerable<StudentClass> StudentClasses { get; set; }

    public Class()
    {
        Id = new Guid();
    }

    public Class(Guid id)
    {
        Id = id;
    }
}

When I generate my migrations I get a foreign key of TeacherId in the Classes table as expected.当我生成迁移时,我按预期在 Classes 表中得到了一个外键TeacherId Here is the SQL:这是 SQL:

CREATE TABLE [dbo].[Classes] (
[Id]        UNIQUEIDENTIFIER NOT NULL,
[Name]      NVARCHAR (20)    NOT NULL,
[Capacity]  INT              NOT NULL,
[TeacherId] UNIQUEIDENTIFIER NULL,
CONSTRAINT [PK_Classes] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Classes_Teachers_TeacherId] FOREIGN KEY ([TeacherId]) REFERENCES [dbo].[Teachers] ([Id])
);
GO
CREATE NONCLUSTERED INDEX [IX_Classes_TeacherId]
ON [dbo].[Classes]([TeacherId] ASC);

My class derived of DBContext looks like:我的DBContext派生类如下所示:

public class SchoolDatabaseContext : DbContext
{
    public DbSet<Student> Students { get; private set; }
    public DbSet<Class> Classes { get; private set; }
    public DbSet<Teacher> Teachers { get; private set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

    }

    public SchoolDatabaseContext(DbContextOptions<SchoolDatabaseContext> options) : base(options)
    {
    }
}

No configuration for those entities yet.这些实体还没有配置。 I use DI to serve the DbContext to the controller and that all seems fine.我使用 DI 将DbContext 提供给控制器,一切看起来都很好。

I have aimed for a DDD type structure, but to make this issue easier to debug I have stripped everything all the way back to the controller so it is basically... controller => DbContext .我的目标是 DDD 类型的结构,但为了使这个问题更容易调试,我已经将所有内容都剥离回控制器,因此它基本上是... controller => DbContext

Here is my code in the controller:这是我在控制器中的代码:

[HttpPost]
    [Route("assign-teacher-to-class")]
    public async Task<IActionResult> AssignClass([FromBody] AssignTeacherToClass assignTeacherToClass)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var teacher = await schoolDatabaseContext.Teachers.FindAsync(assignTeacherToClass.TeacherId);

        var classToAssign = await schoolDatabaseContext.Classes.FindAsync(assignTeacherToClass.ClassId);


        teacher.AssignClass(classToAssign);

        schoolDatabaseContext.Entry(teacher).State = EntityState.Modified;

        await schoolDatabaseContext.SaveChangesAsync();

        return Ok(teacher);
}

When I debug through the ids are fine from the post body, they are assigned correctly to the DTO AssignClass and the calls to the DbContext to find the data for each type (teacher and class) are fine.当我通过帖子正文中的 id 进行调试时,它们被正确分配给 DTO AssignClass并且调用DbContext以查找每种类型(教师和班级)的数据都很好。 I then call a method in my teacher type to add the class to the List Classes property (see teachers entity code at beginning for reference), I then Save the changes with the DbContext method and Problem Defined Here: at no stage does the TeacherId in the database update whilst debugging/completing.然后我打电话的方法在我的老师类型的类添加到列表类财产(见老师实体代码在开始供参考),然后我保存用的DbContext方法和问题定义这里的变化在任何阶段做的TeacherId在调试/完成时数据库更新。 I have tried all I can think of like instantiating collections in different ways, changing collection types, looking for config that might help map these entities in this way, stripping out all extra layers, changing accessibility of properties and classes and few more.我已经尝试了所有我能想到的方法,例如以不同的方式实例化集合、更改集合类型、寻找可能有助于以这种方式映射这些实体的配置、剥离所有额外层、更改属性和类的可访问性等等。

Any help would really be appreciated as I am getting a bit defeated on this one and I feel like this relationship should be fairly straight forward.任何帮助都将不胜感激,因为我在这个问题上有点失败,我觉得这种关系应该是相当直接的。 I actually was able to get my many to many working with a bridge class so I was surprised to get stuck on this one :(我实际上能够让我的多对多工作与桥梁课程一起工作,所以我很惊讶被困在这个课程上:(

Thanks谢谢

try this:尝试这个:

 var teacher = await schoolDatabaseContext.Teachers.Include(x => x.Classes).SingleOrDefaultAsync(x => x.Id == assignTeacherToClass.TeacherId);

I don't think teacher.Classes gets tracked by DbContext otherwise.否则我不认为teacher.Classes会被DbContext跟踪。

There are multiple ways to accomplish this with EF Core.使用 EF Core 有多种方法可以实现这一点。 It is easiest to find if you call it what the docs call it "Related Data".如果您称其为文档所称的“相关数据”,则最容易找到。

Here is the parent doc:Related Data这是父文档:相关数据

Specifically as @Y Stroli has illustrated the Eager Loading method.特别是@Y Stroli 已经说明了Eager Loading方法。

The below example is shown on the eager loading reference to load multiple levels of related data:下面的示例显示在预先加载参考中以加载多个级别的相关数据:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
                .ThenInclude(author => author.Photo)
        .ToList();
}

As of EF Core 5.0 you can also do filtered includes:从 EF Core 5.0 开始,您还可以过滤包含:

using (var context = new BloggingContext())
{
    var filteredBlogs = context.Blogs
        .Include(blog => blog.Posts
            .Where(post => post.BlogId == 1)
            .OrderByDescending(post => post.Title)
            .Take(5))
        .ToList();
}

As the suggestion from lvan, you should change public List<Class> Classes = new List<Class>();根据 lvan 的建议,您应该更改public List<Class> Classes = new List<Class>(); to public List<Class> Classes { get; set; } = new List<Class>();public List<Class> Classes { get; set; } = new List<Class>(); public List<Class> Classes { get; set; } = new List<Class>(); . .

For your current code, it seems you want to add Class and return the teacher , if so, you need to include the exsiting classes to teacher like below, otherwise, it will only return the new adding class.对于您当前的代码,您似乎想添加Class并返回teacher ,如果是这样,则需要将现有的classes包含到teacher中,如下所示,否则,它只会返回新添加的课程。

    public async Task<IActionResult> AssignClass()
    {
        var assignTeacherToClass = new AssignTeacherToClass {
            TeacherId = new Guid("52abe5e0-bcd4-4827-893a-26b24ca7b1c4"),
            ClassId =new Guid("50354c76-c9e8-4fc3-a7c9-7644d47a6854")
        };
        var teacher = await _context.Teachers.Include(t => t.Classes).FirstOrDefaultAsync(t => t.Id == assignTeacherToClass.TeacherId);
        var classToAssign = await _context.Classes.FindAsync(assignTeacherToClass.ClassId);
        teacher.AssignClass(classToAssign);
        _context.Entry(teacher).State = EntityState.Modified;
        await _context.SaveChangesAsync();
        return Ok(teacher);
    }

One more note, you need to configure SerializerSettings.ReferenceLoopHandling like再注意一点,你需要配置SerializerSettings.ReferenceLoopHandling类的

services.AddMvc()
        .AddJsonOptions(opt => {
            opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

You need to define the connection between Teacher and Class.您需要定义教师和班级之间的连接。

protected override void OnModelCreating(Modelbuilder modelBuilder)
{
    modelBuilder.Entity<Class>()
        .HasOne<Teacher>(p => p.Teacher)
        .WithMany(q => q.Classes)
        .HasForeignKey(r => r.TeacherId);
}

Also add TeacherId prop to Class.还将 TeacherId 道具添加到 Class。

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

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