Bla*_*mes 2 c# entity-framework entity-framework-core .net-core asp.net-core-2.1
我有一个实体 forUsers和一个实体 for Projects。
我需要能够将多个用户分配给我的项目实体上的 3 个不同列表属性。我已经能够通过连接实体成功地为一个属性(多对多关系)执行此操作。我可以UserType在 Users 表上指定并且只使用一个属性,但我可能会遇到这样的情况,即用户可能执行多个角色(类型),然后就行不通了。
我以为我可以将UserType放在连接表(实体)上,但我不知道如何在我的 DBContext 中构建该实体。
这是我使用定义的一个属性工作的内容:
项目实体:
public class Project : IInt32Identity
{
public int Id { get; set; }
public string ProjectName { get; set; }
...
public bool ProjectActive { get; set; }
public List<ProjectFile> ProjectFiles { get; set; }
public List<ProjectUsers> ProjectUsers { get; set; }
public DateTime ProjectCreatedDate { get; set; }
public DateTime ProjectModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
用户实体:
public class User : IInt32Identity
{
public int Id { get; set; }
public string UserEmail { get; set; }
...
public List<ProjectUsers> ProjectUsers { get; set; }
public DateTime UserCreatedDate { get; set; }
public DateTime UserLastLoggedInDate { get; set; }
public DateTime UserModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
加入实体:
public class ProjectUsers
{
public int UserId { get; set; }
public User User { get; set; }
public int ProjectId { get; set; }
public Project Project { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
而我OnModelCreating()在我的 DBContext 中
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProjectUsers>()
.HasKey(bc => new { bc.UserId, bc.ProjectId });
modelBuilder.Entity<ProjectUsers>()
.HasOne(bc => bc.User)
.WithMany(b => b.ProjectUsers)
.HasForeignKey(bc => bc.UserId);
modelBuilder.Entity<ProjectUsers>()
.HasOne(bc => bc.Project)
.WithMany(c => c.ProjectUsers)
.HasForeignKey(bc => bc.ProjectId);
}
Run Code Online (Sandbox Code Playgroud)
正如我上面所说,一切正常,但这是我想要的:
项目实体:
public class Project : IInt32Identity
{
public int Id { get; set; }
public string ProjectName { get; set; }
...
public bool ProjectActive { get; set; }
public List<ProjectFile> ProjectFiles { get; set; }
public List<ProjectUsers> ProjectClients { get; set; }
public List<ProjectUsers> ProjectBuilders { get; set; }
public List<ProjectUsers> ProjectDesigners { get; set; }
public DateTime ProjectCreatedDate { get; set; }
public DateTime ProjectModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
UserEntity 是一样的。
加入实体:
public class ProjectUsers
{
public int UserId { get; set; }
public User User { get; set; }
public int ProjectId { get; set; }
public Project Project { get; set; }
public string UserType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我迷失的地方是OnModelBinding()代码,我也不确定 EF 是否足够智能以根据该UserType元属性正确填充列表。
任何帮助或指导将不胜感激。
TIA
这似乎可以把ProjectUser作为基类/实体,并为创建不同的类/实体/类型ProjectClient,ProjectBuilder以及ProjectDesigner那些从继承ProjectUser。然后为每种类型创建表以及与项目的一对多关系。这通常称为按类型表 (TPT)方法。
但是,TPT尚未在 EF Core 中实现。
您仍然可以实现它使用表,每个层级(TPH) ,但你会在该项目中的所有项目的用户,其中只有一个列表UserId,ProjectId并UserType成为复杂的关键。项目客户、建筑商和设计师将根据该项目用户列表计算属性。
public class Project
{
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<ProjectUser> ProjectUsers { get; set; }
public IEnumerable<ProjectUser> ProjectClients => this.ProjectUsers
.Where(x => x.UserType == "Client");
public IEnumerable<ProjectUser> ProjectBuilders => this.ProjectUsers
.Where(x => x.UserType == "Builder");
public IEnumerable<ProjectUser> ProjectDesigners => this.ProjectUsers
.Where(x => x.UserType == "Designer");
}
public class User
{
public int Id { get; set; }
public string Email { get; set; }
public virtual ICollection<ProjectUser> UserProjects { get; set; }
}
public class ProjectUser
{
public int UserId { get; set; }
public virtual User User { get; set; }
public int ProjectId { get; set; }
public virtual Project Project { get; set; }
public string UserType { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
public class ProjectConfiguration : IEntityTypeConfiguration<Project>
{
public void Configure(EntityTypeBuilder<Project> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Name).IsRequired();
builder.HasIndex(x => x.Name).IsUnique();
builder.Ignore(x => x.ProjectBuilders);
builder.Ignore(x => x.ProjectClients);
builder.Ignore(x => x.ProjectDesigners);
builder.ToTable("Project");
}
}
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.HasKey(x => x.Id);
builder.Property(x => x.Email).IsRequired();
builder.HasIndex(x => x.Email).IsUnique();
builder.ToTable("User");
}
}
public class ProjectUserConfiguration : IEntityTypeConfiguration<ProjectUser>
{
public void Configure(EntityTypeBuilder<ProjectUser> builder)
{
builder.HasKey(x => new { x.ProjectId, x.UserId, x.UserType });
builder.Property(x => x.UserType).IsRequired();
builder.HasOne(x => x.Project)
.WithMany(x => x.ProjectUsers)
.HasForeignKey(x => x.ProjectId);
builder.HasOne(x => x.User)
.WithMany(x => x.UserProjects)
.HasForeignKey(x => x.UserId);
}
}
Run Code Online (Sandbox Code Playgroud)
该virtual关键字是有延迟加载的支持。如果您不进行延迟加载,则不必在virtual那里进行。此外,您还必须使用[NotMapped]这 3 个计算属性,这与.Ignore在 fluent API 中使用相同。
public class AppDbContext : DbContext
{
public DbSet<Project> Projects { get; set; }
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new ProjectConfiguration());
modelBuilder.ApplyConfiguration(new UserConfiguration());
modelBuilder.ApplyConfiguration(new ProjectUserConfiguration());
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder
.UseLazyLoadingProxies()
.UseSqlServer("Data Source=.\\SQLEXPRESS;Initial Catalog=DL.SO.ProjectUsersDemo;Integrated Security=True;MultipleActiveResultSets=False;");
}
}
Run Code Online (Sandbox Code Playgroud)
这里没什么特别的。添加迁移并更新数据库后,您的应该看起来像
使用示例数据为数据库播种后,虽然这里很难显示,但您可以看到这 3 个列表填充了正确的数据: