0

我正在尝试遵循Jimmy Bogard关于避免 ORM 中的多对多映射的想法

鉴于此设置,我还希望能够直接公开关系中的“加入”对象。

对象

  • 用户
  • 角色
  • 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);
}

只要我将一个 DBset 添加到 UserRoles 对象的 DbContext 中。EF 找不到 UserRoles 对象的 PK。

UserRoles:EntityType:EntitySet 'UserRoles' 基于没有定义键的类型'UserRole'。

然后我尝试像这样指定密钥:

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

但是 EF 不知道我想使用相同的 UserRoles 表,因为它为该对象添加了第二个表。

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

如何指示 DbModelBuilder 我只想使用单个 UserRole 表?

我在github上有一个针对这个问题的演示 .sln

4

1 回答 1

2

我认为您将两件事混合在一起。

如果要公开M:N表,则不能M:N在 Entity Framework 中使用关联,因为 Entity Framework 会为您隐藏它。然后,您应该将其映射为两个1:MN:1关联。在这种情况下,您强制实体框架以这种方式而不是M:N. 当您自己查询此关联时,您必须指定所有条件(这可能是您想要做的)。基本上是代表您加入实体框架。

但你也可以同时使用这两个世界。尽管这可能很危险,但您必须小心地进行更新、删除等操作。您可以创建一个视图,即MyUserRoles只是select * from UserRoles并将其映射为UserRoles实体的后备“表”。但是正如我所说,您应该非常小心更改,因为您可能会DbContext通过更改MyUserRoles而很容易混淆 Entity Framework 认为M:N.

于 2014-05-17T15:28:23.543 回答