[英]Foreign key not populating in Entity Framework
我無法正確更新應該鏈接我的兩個實體的表。 更詳細地解釋......我有兩個實體Class和Teacher ,它們的關系為:
下面是這兩個實體。
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.