复合主键作为多对多关系中的阴影属性

时间:2017-08-07 11:06:38

标签: c# entity-framework-core ef-fluent-api

我正在使用.NET Core end Entity Framework核心来构建两个实体之间的多对多关系。我已经建立了连接实体来完全填充关系和基于阴影属性的主键,如下所示:

实体用户:

public class User
{
    [Key]
    public int IDUser { get; set; }
    [Required]
    public string Forename { get; set; }

    public List<UserGroup> UsersGroups { get; set; }
}

实体组:

public class Group
{
    [Key]
    public int IDGroup { get; set; }
    [Required]
    public string GroupName { get; set; }

    public List<UserGroup> UsersGroups { get; set; }
}

实体用户组:

public class UserGroup
{
    public Group Group { get; set; }
    public User User { get; set; }
}

DBcontext类:

public class DBContext : DbContext
{
    public DBContext(DbContextOptions<DBContext> options)
        : base(options)
    {

    }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // shadow property - primary/foreign key
        modelBuilder.Entity<UserGroup>()
            .Property<int>("IDUser");

        // shadow property - primary/foreign key
        modelBuilder.Entity<UserGroup>()
            .Property<int>("IDGroup");

        // composite primary key based on shadow properties
        modelBuilder.Entity<UserGroup>()
            .HasKey( new string[]{ "IDUser", "IDGroup" });

        modelBuilder.Entity<UserGroup>()
            .HasOne(ug => ug.Group)
            .WithMany(g => g.UsersGroups)
            .HasForeignKey(???); //what to do here ?

        modelBuilder.Entity<UserGroup>()
            .HasOne(ug => ug.User)
            .WithMany(u => u.UsersGroups)
            .HasForeignKey(???); // what to do here ?

        base.OnModelCreating(modelBuilder);
    }

    public DbSet<Group> Groups { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<UserGroup> UserGroups { get; set; }
}

现在。如何根据我的影子复合主键在UserGroup实体上正确建立外键?我希望这个影子主键同时是外键。我现在不知道如何引用这个影子主键来制作外键。我标记了我不知道如何处理问号。

2 个答案:

答案 0 :(得分:2)

.HasForeignKey()在您的实体上声明外键属性。

如果您不想在链接实体上使用外键属性(并且您应该拥有它们),只需省略.HasForeignKey声明,EF将按惯例使用映射FK列。

例如

   protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // shadow property - primary/foreign key
        modelBuilder.Entity<UserGroup>()
            .Property<int>("IDUser");

        // shadow property - primary/foreign key
        modelBuilder.Entity<UserGroup>()
            .Property<int>("IDGroup");

        // composite primary key based on shadow properties
        modelBuilder.Entity<UserGroup>()
            .HasKey(new string[] { "IDUser", "IDGroup" });

        modelBuilder.Entity<UserGroup>()
            .HasOne(ug => ug.Group)
            .WithMany(g => g.UsersGroups);
        //.HasForeignKey(???); //what to do here ?

        modelBuilder.Entity<UserGroup>()
            .HasOne(ug => ug.User)
            .WithMany(u => u.UsersGroups);
            //.HasForeignKey(???); // what to do here ?

        base.OnModelCreating(modelBuilder);
    }

生成

CREATE TABLE [UserGroups] (
    [IDUser] int NOT NULL,
    [IDGroup] int NOT NULL,
    CONSTRAINT [PK_UserGroups] PRIMARY KEY ([IDUser], [IDGroup]),
    CONSTRAINT [FK_UserGroups_Groups_IDGroup] FOREIGN KEY ([IDGroup]) REFERENCES [Groups] ([IDGroup]) ON DELETE CASCADE,
    CONSTRAINT [FK_UserGroups_Users_IDUser] FOREIGN KEY ([IDUser]) REFERENCES [Users] ([IDUser]) ON DELETE CASCADE
);

答案 1 :(得分:2)

您正在尝试创建多对多连接表而不定义任何标量属性,并且您正在使用shadow属性来配置连接表。对于EF fluent API,您必须引用shadow属性,您需要使用基于字符串的方法。由于缺乏支持CLR属性,lambda表达式不起作用。

在你的情况下,&#34;在这里做什么&#34; part只是使用属性的字符串名称。 e.g。

modelBuilder.Entity<UserGroup>()
    .HasOne(ug => ug.Group)
    .WithMany(g => g.UsersGroups)
    .HasForeignKey("IDGroup"); //what to do here ?

其他关系相同。当您要将shadow属性配置为外键属性时,这是一般机制。此外,在HasForeignKey中配置shadow属性不需要事先定义shadow属性,因为EF可以根据关系主体侧的属性推断类型。虽然对于HasKey,您仍然需要声明阴影属性,因为EF不知道类型。 (正如你在你的例子中所做的那样)

EF Core也有约定FK属性的惯例。其中一个惯例是,如果属性与主要属性相同,则将属性用作FK。在上面的特殊情况下,由于您的主要主键属性命名为IDGroup,它与您尝试配置的外键相同,因此EF将按惯例自动使用该属性。这意味着您可以忽略配置您的关系(如@David建议)。此外,由于EF发现基于导航的关系,您可以从应用程序中完全删除以下代码,它将创建相同的模型。

modelBuilder.Entity<UserGroup>()
    .HasOne(ug => ug.Group)
    .WithMany(g => g.UsersGroups);
//.HasForeignKey(???); //what to do here ?

modelBuilder.Entity<UserGroup>()
    .HasOne(ug => ug.User)
    .WithMany(u => u.UsersGroups);
    //.HasForeignKey(???); // what to do here ?