【问题标题】:Self-referencing many-to-many recursive relationship code first Entity Framework自引用多对多递归关系代码优先实体框架
【发布时间】:2011-07-04 17:56:13
【问题描述】:

我似乎根本无法完成这项工作

class Member
{
    public virtual IList<Member> Friends { get; set; }
    [Key]
    public int MemberId { get; set; }
    public string Name{ get; set; }
}

我尝试添加映射但徒劳无功。有没有办法用 CTP5 做到这一点?

【问题讨论】:

  • 我认为这与代码无关,但请查看this post

标签: c# entity-framework many-to-many code-first


【解决方案1】:

按照惯例,Code First 将单向关联视为一对多。因此,您需要使用 fluent API 让 Code First 知道您想要拥有多对多自引用关联:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Member>().HasMany(m => m.Friends).WithMany().Map(m =>
        {
            m.MapLeftKey("MemberId");
            m.MapRightKey("FriendId");
            m.ToTable("MembersFriends");
        }
    );
}

【讨论】:

  • Morteza,我一直在这里和你的博客上关注你。这完美无瑕!虽然结果表被命名为 [MemberMembers],这很奇怪,但将在 RTM 中修复。谢谢老哥!
  • 你好,我想知道我们如何使用多个自引用。例如在相同的示例代码上; public virtual IList Friends { get;放; } 公共虚拟 IList 父母 { 得到;放; }
  • 这很好用,谢谢。你知道有没有指定它将创建的多对多表的名称? MemberMembers 工作正常,但看起来很难看。
  • @Morteza 当我添加 HasMany 时,我没有选择链接 WithMany,
  • 我如何在最新的 EF 核心中做到这一点
【解决方案2】:

如果我是正确的,您可以使用以下代码影响多对多表名称:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Member>().HasMany(m => m.Friends).WithMany().Map(m =>
        {
            m.MapLeftKey("MemberId");
            m.MapRightKey("FriendId");
            m.ToTable("MembersFriends");
        }
    );
}

希望这会有所帮助。

【讨论】:

    【解决方案3】:

    您可以使用 Model-First 使其在 EF 4 CTP5 中工作,但 CTP5 Code First 存在太多错误,具有自引用和多态查询配置,无法在此类情况下使用 Code First。 Morteza Manavi(见其他答案)在他的博客上记录了其中的几个。

    【讨论】:

    • 确实如此。希望 RTM 满足我们的要求。代码优先真是太棒了!
    【解决方案4】:

    我想在不编写流畅的 API 代码的情况下完成这项工作。所以这是我的看法。

    以下示例尝试保存用户访问过的任何其他用户个人资料以及访问过该用户个人资料的人。遗憾的是,以下示例不支持除了访问和访问用户的两个 id 之外的其他属性。

    导航属性已使用 InversePropertyAttribute 链接。
    entityframework.netentityframeworktutorial.net 中查看更多信息

    型号↴

    public class User
    {   
        [InverseProperty(nameof(User.VisitingUsers))]
        public virtual List<User> VisitedUsers { get; set; }
        [NotMapped]
        public long? VisitedUsersCount { get { return this.VisitedUsers == null ? 0 : this.VisitedUsers.Count(); } }
    
        [InverseProperty(nameof(User.VisitedUsers))]
        public virtual List<User> VisitingUsers { get; set; }
        [NotMapped]
        public long? VisitingUsersCount { get { return this.VisitingUsers == null ? 0 : this.VisitingUsers.Count(); } }
    }
    

    生成的迁移代码↴

    CreateTable(
        "dbo.UserUsers",
        c => new
        {
            User_Id = c.Long(nullable: false),
            User_Id1 = c.Long(nullable: false),
        })
        .PrimaryKey(t => new { t.User_Id, t.User_Id1 })
        .ForeignKey("dbo.Users", t => t.User_Id)
        .ForeignKey("dbo.Users", t => t.User_Id1)
        .Index(t => t.User_Id)
        .Index(t => t.User_Id1);
    

    【讨论】:

    • 这甚至可以在没有 InverseProperty 属性的情况下工作,只要有两个用户集合。 EF 会自动假定它们是对应的。
    【解决方案5】:

    您的示例不是多对多关系,它更像是一种递归关系。

    我不知道如何解决它。但是您的代码的问题是您将在同一行上获得两个具有相同名称的字段。 MemberId 为行的 id,MemberId 为朋友的 id。

    编辑

    尝试这样做:

        class Member 
        { 
            [Key]
            public int MemberId { get; set; } 
            public string Name { get; set; }
    
            public virtual IList<FriendRelationship> Friends { get; set; } 
    
        }
    
        class FriendRelationship
        {
            [Key]
            public int RelationshipId { get; set; }
    
            public Member Friend { get; set; }
        }
    

    【讨论】:

    • 对我来说它可以是多对多的,因为它可以通过引入带有 [LeftMemberId] 和 [RightMemberId] 的表 [Friends] 来解决。不管命名是否正确,我都无法让它工作:(
    • 谢谢伙计,我没有得到改变来尝试你的解决方案,但这是我手动执行的最初解决方案。等不及 RTM :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 2013-02-26
    相关资源
    最近更新 更多