簡體   English   中英

實體框架中未填充外鍵

[英]Foreign key not populating in Entity Framework

我無法正確更新應該鏈接我的兩個實體的表。 更詳細地解釋......我有兩個實體ClassTeacher ,它們的關系為:

  1. 老師可以分配到多個班級
  2. 班級只能有一位老師。

下面是這兩個實體。

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;
    }
}

當我生成遷移時,我按預期在 Classes 表中得到了一個外鍵TeacherId 這是 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);

我的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)
    {
    }
}

這些實體還沒有配置。 我使用 DI 將DbContext 提供給控制器,一切看起來都很好。

我的目標是 DDD 類型的結構,但為了使這個問題更容易調試,我已經將所有內容都剝離回控制器,因此它基本上是... controller => DbContext

這是我在控制器中的代碼:

[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);
}

當我通過帖子正文中的 id 進行調試時,它們被正確分配給 DTO AssignClass並且調用DbContext以查找每種類型(教師和班級)的數據都很好。 然后我打電話的方法在我的老師類型的類添加到列表類財產(見老師實體代碼在開始供參考),然后我保存用的DbContext方法和問題定義這里的變化在任何階段做的TeacherId在調試/完成時數據庫更新。 我已經嘗試了所有我能想到的方法,例如以不同的方式實例化集合、更改集合類型、尋找可能有助於以這種方式映射這些實體的配置、剝離所有額外層、更改屬性和類的可訪問性等等。

任何幫助都將不勝感激,因為我在這個問題上有點失敗,我覺得這種關系應該是相當直接的。 我實際上能夠讓我的多對多工作與橋梁課程一起工作,所以我很驚訝被困在這個課程上:(

謝謝

嘗試這個:

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

否則我不認為teacher.Classes會被DbContext跟蹤。

使用 EF Core 有多種方法可以實現這一點。 如果您稱其為文檔所稱的“相關數據”,則最容易找到。

這是父文檔:相關數據

特別是@Y Stroli 已經說明了Eager Loading方法。

下面的示例顯示在預先加載參考中以加載多個級別的相關數據:

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

從 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();
}

根據 lvan 的建議,您應該更改public List<Class> Classes = new List<Class>(); public List<Class> Classes { get; set; } = new List<Class>(); public List<Class> Classes { get; set; } = new List<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);
    }

再注意一點,你需要配置SerializerSettings.ReferenceLoopHandling類的

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

您需要定義教師和班級之間的連接。

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

還將 TeacherId 道具添加到 Class。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM