实体框架和关系

Posted

技术标签:

【中文标题】实体框架和关系【英文标题】:Entity Framework and relationships 【发布时间】:2012-07-23 10:52:17 【问题描述】:

我在 VS 2012 RC 上使用 EF 5 rc 并遇到了一些问题。很确定这与我在数据库和 EF 方面的知识有关,而不是我使用的软件的版本号 :)

所以,我有 3 节课。用户、角色和权利。

用户类

public class User

    [Key]
    public int UserId  get; private set; 

    [Required]
    public string EmailAddress  get; internal set; 

    [Required]
    public string Username  get; internal set; 

    public ICollection<Role> Roles  get; set; 

    // More properties 

正确的类

public class Right

    public virtual int RightId  get; set; 
    public virtual string Description  get; set; 

角色类

public class Role

    public virtual int RoleId  get; set; 
    public virtual string Description  get; set; 

    public virtual ICollection<Right> Rights  get; set; 

上下文

 class MyContext : DbContext
 
    public virtual DbSet<User> Users  get; set; 
    public virtual DbSet<Role> Roles  get; set; 
    public virtual DbSet<Right> Rights  get; set; 
 

现在,我想将 roles 添加到 user,并将 rights 添加到 role。但我也想确保可以添加相同的Right 可以添加到不同的roles

 var role1 = new Role()

     Description = "role1"
;

var role2 = new Role()

    Description = "role2"
;

var right = new Right()

    Description = "right"
;

context.Rights.Add(right);
context.Roles.Add(role1);
context.Roles.Add(role2);

role1.Rights = new List<Right>();
role2.Rights = new List<Right>();
role1.Rights.Add(right);
role2.Rights.Add(right);

 /**** ERROR ****/
context.SaveChanges();

我来了

InvalidOperationException:违反多重性约束。关系“Role_Rights”的角色“Role_Rights_Source”具有多重性 1 或 0..1。

我做错了什么? 另外,我对创建一个像

这样的新列表感觉不妥
 role1.Rights = new List<Right>();
 role2.Rights = new List<Right>();

推荐的方法是什么?权利属性为空。所以我不能在不更新的情况下添加任何东西。

【问题讨论】:

【参考方案1】:

问题在于 EF 用于推断关系的约定。它认为关系是一对多但你想要多对多(角色可以有多个权限,并且权限可以用于多个角色)。

有两种方法可以解决这个问题:

选项 1:在右侧创建导航属性:

public class Right

    public virtual int RightId  get; set; 
    public virtual string Description  get; set; 

    public virtual ICollection<Role> Roles  get; set; 

现在 EF 约定将检测关系两侧的集合并正确使用多对多多重性而不是一对多

选项 2:使用 Fluent-API 告诉 EF 您需要多对多关系:

public class MyContext : DbContext

    public virtual DbSet<User> Users  get; set; 
    public virtual DbSet<Role> Roles  get; set; 
    public virtual DbSet<Right> Rights  get; set; 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        modelBuilder.Entity<Role>()
                    .HasMany(r => r.Rights)
                    .WithMany();
    

现在 EF 知道 Right 可以分配给多个角色,即使 Right 没有 Role 的导航属性。

如果Role 可以分配给多个用户,您也必须使用多对多关系

【讨论】:

哇,您刚刚解决了过去 3 天让我无法入睡的问题。 (显示我对 EF 有多么出色。)我假设,使用 选项 1 如果我将角色添加到权限,EF 还将映射该角色将拥有权限? 是 - EF 将在数据库内部创建联结表以处理多对多关系。【参考方案2】:

Ladislav 的答案应该可以很好地解决该错误。

关于您对使用感到不舒服的问题:

role1.Rights = new List<Right>();

您应该在构造函数中将这些属性初始化为新的列表,然后将为所有角色实例完成:

public class Role

    public virtual int RoleId  get; set; 
    public virtual string Description  get; set; 

    public virtual ICollection<Right> Rights  get; set; 

public Role ()

this.Rights =  new List<Right>();    


【讨论】:

非常感谢...这将为我节省很多空检查... :) 如果你需要很多,不要在你用模型生成数据库之后。只需通过从数据库重新创建模型来向后工作,EF 也会使用一些 Fluent 映射自动添加这些 sql-server-performance.com/2012/…

以上是关于实体框架和关系的主要内容,如果未能解决你的问题,请参考以下文章

我应该如何在实体框架中创建这种关系?

使用 SQL 和 Linq 的多对多关系(实体框架/实体)

尽管代理被禁用,实体框架会自动设置关系

实体框架中的形态关系

实体框架中的问题建模关系首先使用代码

多对多关系实体框架核心db优先