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にあります