0

ORM での多対多マッピングの回避に関するJimmy Bogardのこのアイデアに従おうとしています。

このセットアップを考えると、関係で「結合」オブジェクトも直接公開できるようにしたいと考えています。

オブジェクト

  • ユーザー
  • 役割
  • UserRole (関連オブジェクト)

コード:

public class User
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Role> Roles { get; set; }
}

public class Role
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<User> Users { get; set; }
}

public class UserRole
{
    public Guid UserId { get; set; }
    public Guid RoleId { get; set; }
    public User User { get; set; }
    public Role Role { get; set; }
}

public class MyContext : DbContext 
{

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        //modelBuilder.Entity<UserRole>().HasKey(u => new { u.RoleId, u.UserId });
        modelBuilder.Entity<User>().HasMany(x => x.Roles).WithMany(x => x.Users).Map(m =>
        {
            m.ToTable("UserRoles");
            m.MapLeftKey("UserId");
            m.MapRightKey("RoleId");
        });
    }

    public DbSet<User> Users { get; set; }
    public DbSet<Role> Roles { get; set; }
    //public DbSet<UserRole> UserRoles { get; set; } 
}

これに移行を追加すると、期待どおりになります。

public override void Up()
{
    CreateTable(
        "dbo.Roles",
        c => new
            {
                Id = c.Guid(nullable: false),
                Name = c.String(),
            })
        .PrimaryKey(t => t.Id);

    CreateTable(
        "dbo.Users",
        c => new
            {
                Id = c.Guid(nullable: false),
                Name = c.String(),
            })
        .PrimaryKey(t => t.Id);

    CreateTable(
        "dbo.UserRoles",
        c => new
            {
                UserId = c.Guid(nullable: false),
                RoleId = c.Guid(nullable: false),
            })
        .PrimaryKey(t => new { t.UserId, t.RoleId })
        .ForeignKey("dbo.Users", t => t.UserId, cascadeDelete: true)
        .ForeignKey("dbo.Roles", t => t.RoleId, cascadeDelete: true)
        .Index(t => t.UserId)
        .Index(t => t.RoleId);
}

UserRoles オブジェクトの DbContext に DBset を追加するとすぐに。EF は UserRoles オブジェクトの PK を見つけることができません。

UserRoles: EntityType: EntitySet 'UserRoles' は、キーが定義されていないタイプ 'UserRole' に基づいています。

次に、次のようにキーを指定してみます。

modelBuilder.Entity<UserRole>().HasKey(u => new { u.RoleId, u.UserId });

しかし、EF は、同じ UserRoles テーブルを使用したいことを知りません。これは、そのオブジェクトの 2 番目のテーブルを追加するためです。

CreateTable(
"dbo.UserRoles1",
c => new
    {
        RoleId = c.Guid(nullable: false),
        UserId = c.Guid(nullable: false),
    })
.PrimaryKey(t => new { t.RoleId, t.UserId })
.ForeignKey("dbo.Roles", t => t.RoleId, cascadeDelete: true)
.ForeignKey("dbo.Users", t => t.UserId, cascadeDelete: true)
.Index(t => t.RoleId)
.Index(t => t.UserId);

単一の UserRole テーブルのみを使用するように DbModelBuilder に指示するにはどうすればよいですか?

この問題のデモ .sln がgithubにあります

4

1 に答える 1