EF Core 5 TPT 和身份 (CRUD)
Posted
技术标签:
【中文标题】EF Core 5 TPT 和身份 (CRUD)【英文标题】:EF Core 5 TPT and Identity (CRUD) 【发布时间】:2021-03-25 14:13:22 【问题描述】:我想使用 EF Core 的 TPT 功能,我想将它与 Identity 集成,但我在添加到数据库时遇到了一些问题。
public class ApplicationUser : IdentityUser<Guid>
public string FirstName get; set;
public string LastName get; set;
public string NationalCode get; set;
public DateTime BirthDate get; set;
public Gender Gender get; set;
public class Student : ApplicationUser
public string FatherName get; set;
public string PlaceOfBirth get; set;
public string Address get; set;
public string HomePhoneNumber get; set;
public class Teacher : ApplicationUser
public string FieldOfStudy get; set;
public AcademicDegree AcademicDegree get; set;
public int YearsOfExperience get; set;
这是我的数据库上下文类
public class SchoolMgmtContext : IdentityDbContext<ApplicationUser,ApplicationRole,Guid>
public SchoolMgmtContext(DbContextOptions<SchoolMgmtContext> dbContextOptions)
:base(dbContextOptions)
public DbSet<Teacher> Teachers get; set;
public DbSet<Student> Students get; set;
protected override void OnModelCreating(ModelBuilder builder)
base.OnModelCreating(builder);
builder.Entity<ApplicationUser>().ToTable("Users");
builder.Entity<Student>().ToTable("Students");
builder.Entity<Teacher>().ToTable("Teachers");
builder.Entity<ApplicationRole>().ToTable("Roles");
一切正常。
但我不知道如何插入新教师或新学生。
例如,这是添加新教师的代码。
public IActionResult CreateTeacher()
ViewBag.Users = new SelectList(_db.Users.Select(u => new u.Id, FullName = u.FirstName + " " + u.LastName ), "Id", "FullName");
return View();
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateTeacher(TeacherCreationDto teacherCreationDto)
if (ModelState.IsValid)
var newTeacher = new Teacher()
AcademicDegree = teacherCreationDto.AcademicDegree,
FieldOfStudy = teacherCreationDto.FieldOfStudy,
YearsOfExperience = teacherCreationDto.YearsOfExperience,
Id= teacherCreationDto.UserId
;
// _db.Teachers.Update(newTeacher); // here I tested Attach - Add - Update, but none of this work.
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
else
ViewBag.Users = new SelectList(_db.Users.Select(u => new u.Id, FullName = u.FirstName + " " + u.LastName ), "Id", "FullName");
return View(teacherCreationDto);
我应该如何添加新的学生或教师?谢谢,
更新:
【问题讨论】:
您添加新 TPT 记录的方式与添加新 TPH 或常规记录的方式相同 - 通过使用某些Add
方法,例如对于新的Teacher
,其中任何一个都应该这样做-_db.Add(newTeacher)
、_db.Users.Add(newTeacher)
、_db.Teachers.Add(newTeacher)
。你是什么意思“没有这个工作”?您是否遇到异常或?
@IvanStoev 感谢您的回答,但这些方法都不起作用,是的,我有 2 个例外,第一个是关于 DbConcurreny,第二个是关于无法插入重复的主键。
这是因为这里 Id= teacherCreationDto.UserId
您正在将现有 ID 分配给新用户(教师)。使用 Id = Guid.NewGuid()
或者不分配它,让 EFC 自动生成它。
@IvanStoev 为什么在 Microsoft docs 或 *** 中没有关于带有 TPT 的 EF Core 5 中的 CRUD 的代码?
嗯,看来你误解了继承的概念。教师是用户,学生也是如此。您不会创建单独的用户并将其“连接”到教师或学生 - 您创建的新教师也是新用户。 TPT 和 TPH 只是在数据库中存储此类继承数据的不同方式。如果您想将对象“连接”到 User,则不应使用继承,而应使用 FK 关系。
【参考方案1】:
我同意“Ivan Stoev”的观点:您不能从 User 继承 Student 和 Teacher。 如果需要,那么您的“TeacherCreationDto”应包含以下字段/有效负载:
“学习领域、经验年限、名字、姓氏、国家代码、出生日期、性别、ID、用户名、规范化用户名、电子邮件、规范化电子邮件、电子邮件确认、密码哈希、SecurityStamp、ConcurrencyStamp、电话号码、电话号码确认、TwoFactorEnabled、LockoutEnd、LockoutEnabled、AccessFailedCount” .. . 当我通过使用自动脚手架创建控制器/api时,以下编码对我有用:
public async Task<IActionResult> Create([Bind("FieldOfStudy,YearsOfExperience,FirstName,LastName,NationalCode,BirthDate,Gender,Id,UserName,NormalizedUserName,Email,NormalizedEmail,EmailConfirmed,PasswordHash,SecurityStamp,ConcurrencyStamp,PhoneNumber,PhoneNumberConfirmed,TwoFactorEnabled,LockoutEnd,LockoutEnabled,AccessFailedCount")] Teacher teacher)
if (ModelState.IsValid)
teacher.Id = Guid.NewGuid();
_context.Add(teacher);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
return View(teacher);
【讨论】:
谢谢,这是我在 Ivan github.com/ArminShoeibi/SchoolManagementSystem 的帮助下创建的示例项目 好吧,除非您的用例暗示Teacher
和Student
是您系统的User
s。但我也同意,通常您将用户与您的应用程序逻辑联系起来,因此在大多数情况下,外键更有可能【参考方案2】:
正如问题作者所说,Microsoft official docs 中没有足够的文档。
与我们对 TPT 的期望相反,当我们想要向派生表中插入新记录时,我们必须提供派生类型(包括父类型)的所有属性,因为 EF Core 会在内部创建两个插入语句,一个用于父表,另一个用于派生表。
因此,如果我们提供现有 id 来创建新记录,则会抛出带有“重复键”消息的 DbUpdateException
。
我可以说,当我们的继承重叠时,这种方法是不合适的(考虑一个用户既是学生又是教师的情况,甚至想从用户更改为学生)。
最后,我建议您手动创建 TPT 关系。你的模型应该是这样的:
public class ApplicationUser : IdentityUser<Guid>
public string FirstName get; set;
public string LastName get; set;
public string NationalCode get; set;
public DateTime BirthDate get; set;
public Gender Gender get; set;
public class Student
[ForignKey(nameof(User))]
public Guid Id get; set; // Id and forignKey
/* Student specific fields */
public ApplicationUser User get; set;
public class Teacher
[ForignKey(nameof(User))]
public Guid Id get; set; // Id and forignKey
/* Teacher specific fields */
public ApplicationUser User get; set;
【讨论】:
以上是关于EF Core 5 TPT 和身份 (CRUD)的主要内容,如果未能解决你的问题,请参考以下文章
使用 EF Code First 继承 – 每个类型的表 (TPT)
Inheritance with EF Code First: Part 2 – Table per Type (TPT)