为什么实体不引用创建它的实体?



我有实体"教师";,它可以创建课程。问题是,当创建一门课程时,由于某种原因,它不记得创建它的老师。老师自己也没有这门课程。更新方法对老师没有帮助。

public async Task<CourseResponse> AddCourse(CourseAddRequest courseAddRequest, Guid teacherId)
{
var teacher = await _teacherRepository.GetTeacher(teacherId);
if (teacher == null)
{
throw new Exception("User doesn't exist");
}
var course = _mapper.Map<Course>(courseAddRequest);
course.Teacher = teacher;
course.TeacherId = teacher.Id;
var addedCourse = await _courseRepository.AddCourse(course);
teacher.Courses.Add(addedCourse);
teacher = await _teacherRepository.UpdateTeacher(teacher);
return _mapper.Map<CourseResponse>(addedCourse);
}

教师:

public class Teacher : BaseEntity
{
public string Name { get; set; }
public string LastName { get; set; }
public List<Course> Courses { get; set; } = new List<Course>();
}

课程:

public class Course : BaseEntity
{
public string Header { get; set; }
public string Description { get; set; }
public Guid TeacherId { get; set; }
public Teacher Teacher { get; set; }
public List<Student> StudentsOnCourse { get; set; } = new List<Student>();
}

我试图组织太多的关系,但无济于事。

class CourseEntityTypeConfiguration : IEntityTypeConfiguration<Course>
{
public void Configure(EntityTypeBuilder<Course> builder)
{
builder.HasOne(c => c.Teacher)
.WithMany(t => t.Courses)
.HasForeignKey(c => c.TeacherId);            

}
}
public class UniDbContext : DbContext
{
public UniDbContext(DbContextOptions<UniDbContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Student> Students { get; set; }
public DbSet<Teacher> Teachers { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(CourseEntityTypeConfiguration).Assembly);

}
}

启动中:

services.AddDbContext<UniDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
sqlOpt => sqlOpt.MigrationsAssembly(typeof(UniDbContext).Assembly.FullName)
));

我有一个git存储库,整个项目都位于该存储库中:https://github.com/ChuvashPeople/UniversityProject

谢谢你的帮助。

我查看了您的来源,几乎可以肯定罪魁祸首是您的"更新";方法:

public async Task<Teacher> UpdateTeacher(Teacher teacher)
{
var oldTeacher = await _uniDbContext.Teachers.FirstOrDefaultAsync(t => t.Id == teacher.Id);
_uniDbContext.Teachers.Remove(oldTeacher);
await _uniDbContext.SaveChangesAsync();
await _uniDbContext.Teachers.AddAsync(teacher);
await _uniDbContext.SaveChangesAsync();
return teacher;
}

这是一种完全错误的更新方式,因为你会被传递的引用绊倒。

我的建议是一开始要简单得多。在你有合法的需求之前,不要使用存储库模式。如果你已经设置了依赖注入,首先只需引用控制器中的DbContext。一旦您了解了这是如何工作的,并希望引入一个存储库来启用单元测试,那么就从中抽象出来。下一个建议是使用同步方法,直到使用async变体有明显的好处为止。async并没有使代码更快,它实际上使代码更慢。它所能做的是,当你需要执行一些可能需要一段时间的事情,或者正在执行一个会被称为"大量"的操作时,让网络服务器更具响应性。按ID更新记录不适合这两种情况。(运行复杂的搜索/报告是一个例子,异步可以帮助避免您的网络服务器陷入困境(

public CourseResponse AddCourse(CourseAddRequest courseAddRequest, Guid teacherId)
{
var teacher = _uniDbContext.Teachers
.Include(t => t.Courses)
.SingleOrDefault(t => t.Id == teacherId);
if (teacher == null)
throw new Exception("User doesn't exist");
var course = _mapper.Map<Course>(courseAddRequest);
teacher.Courses.Add(course);
_uniDbContext.SaveChanges();
return _mapper.Map<CourseResponse>(course);
}

在这里,当你加载一个教师时,包括(热切加载(课程集合,因为你可能还想检查添加的课程是否已经与该教师关联。(未显示(从那里,您只需要将课程添加到加载的教师实体并保存更改。EF将负责将课程与老师联系起来,并设置FK。

我不建议使用EF DbContext之上的Repository模式,除了让单元测试更容易访问之外,它为您提供了一个比尝试模拟DbContext&数据库集。拥有一个返回物化实体或实体集(List<Teacher>等(的存储库效率极低,而且不允许急于加载相关实体、(课程等(过滤、分页或将数据投影到视图实际需要的内容等细节。当您查看存储库周围的单元测试时,我建议您阅读EF中的IQueryable支持,以便存储库可以作为单元测试的精简、可替代的接口,同时仍然提供EF可以提供的所有功能。

**更新**

查看代码的几个细节:

  1. 默认情况下,EF希望遵循默认命名约定("Id"或"TeacherId"等(的PK是SQL Server负责填充PK的标识列。如果要在代码中设置Id,则应将PK列标记为DatabaseGeneratedOption.None。否则,我将删除任何设置默认Id值的代码。这可能会触发FK引用。

  2. 配置关系时,只能从一侧或另一侧进行配置,而不能同时从两者进行配置。如果在教师上配置.HasMany().WithOne(),则删除课程上的.HasOne().WithMany()。理想情况下,引用属性应标记为虚拟,以确保EF可以生成用于更改跟踪的代理。

我不确定这两者是否与该错误有关,但可能是。我知道EF在参考配置加倍时会做一些奇怪的事情。

最新更新