繁体   English   中英

一个实体EF Core 2.2上的多个属性需要多对多关系

[英]Need many to many relationship for multiple properties on one entity EF Core 2.2

我有一个Users实体和一个Projects实体。

我需要能够将多个用户分配给项目实体上的3个不同的列表属性。 我已经能够通过连接实体为一个属性(多对多关系)成功完成此操作。 我可以在“用户”表上指定UserType并仅使用一个属性,但是我可能会遇到以下情况:用户可能会执行多个角色(类型),而这将不起作用。

我以为我可以将UserType放在连接表(实体)上,但是我对如何在DBContext中构建该实体感到困惑。

这是我定义的一个属性的工作:

ProjectEntity:

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

UserEntity:

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

JoinEntity:

public class ProjectUsers
{
    public int UserId { get; set; }
    public User User { get; set; }
    public int ProjectId { get; set; }
    public Project Project { get; set; }
}

还有我在OnModelCreating()

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

就像我上面说的那样,一切都很好,但是这就是我想要的:

ProjectEntity:

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

UserEntity相同。

JoinEntity:

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

我迷路的地方是OnModelBinding()代码,我也不确定EF是否足够聪明,可以根据该UserType元属性正确填充列表。

任何帮助或指导将不胜感激。

TIA

似乎可以将ProjectUser视为基类/实体,并为从ProjectUser继承的ProjectClientProjectBuilderProjectDesigner创建不同的类/实体/类型。 然后为每种类型以及与项目的一对多关系创建表。 这通常称为“ 每种类型的表(TPT)”方法。

但是, TPT尚未在EF Core中实现。

您仍然可以使用每层表(TPH)来实现它,但是对于所有项目用户,项目中只有一个列表,其中UserIdProjectIdUserType成为复杂键。 将根据该项目用户列表从项目客户,建造者和设计师那里计算出属性。

实体

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

配置

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

存在virtual关键字以支持延迟加载。 如果您不进行延迟加载,则不必在那里进行virtual加载。 另外,您还必须[NotMapped]这3个计算出的属性,这与在流利的API方面使用.Ignore相同。

的DbContext

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

这里没什么特别的。 添加迁移并更新数据库后,您的数据库应该看起来像

在此处输入图片说明

用示例数据为数据库播种后,尽管很难在此处显示,但您可以看到这3个列表中填充了正确的数据:

在此处输入图片说明

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM