【问题标题】:Entity Framework 4.1 Code First Self-Referencing One-to-Many and Many-to-Many AssociationsEntity Framework 4.1 Code First 自引用一对多和多对多关联
【发布时间】:2011-09-17 00:50:45
【问题描述】:

我有一个用户可以收集他喜欢的用户...

另一个用户可以拥有他喜欢的用户集合......

如果用户 A 喜欢用户 B,如果用户 B 喜欢用户 A,那么他们就可以出去玩。我需要互相发送他们的联系信息。我们如何在 Entity Framework Code First 中表示这样的模型?

public class User
{
    public int UserId { get; set; }

    public int? UserLikeId { get; set; }
    public virtual UserLike UserLike { get; set; }
}

public class UserLike
{
    public int UserLikeId { get; set; }

    public int UserId { get; set; }
    public virtual User User { get; set; }

    public virtual ICollection<User> LikeUsers { get; set; }
}

这个模型正确吗?我不能让它工作。

我尝试了另一种方法,但也不起作用......

我尝试将用户集合添加到用户表中。

例如:

public virtual ICollection<User> userlike { get; set; }

public class User
{
    public int UserId { get; set; }
    public virtual ICollection<UserLike> UserLikes { get; set; }
}

public class UserLike
{
    public int UserLikeId { get; set; }

    public int UserId { get; set; }
    public virtual User User { get; set; }

    public int LikeUserId { get; set; }
    public virtual User LikeUser { get; set; }
}

当我尝试添加用户和他们喜欢的人时出现此错误:

已检测到对关系“UserLike_LikeUser”的角色“UserLike_LikeUser_Target”的冲突更改。

表示这种模型的最佳方式是什么?

【问题讨论】:

    标签: entity-framework ef-code-first entity-framework-4.1 self-join self-reference


    【解决方案1】:

    你真的不需要一个单独的实体来描述关系,下面的对象模型就可以了:

    public class User
    {
        public int UserId { get; set; }
        public string Name { get; set; }
    
        public int? ThisUserLikesId { get; set; }
        public virtual User ThisUserLikes { get; set; }
        public virtual ICollection<User> LikeThisUser { get; set; }
    }
    
    public class Context : DbContext
    {
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                        .HasOptional(u => u.ThisUserLikes)
                        .WithMany(u => u.LikeThisUser)
                        .HasForeignKey(u => u.ThisUserLikesId);
        }
    }
    

    现在假设您手中有一个 UserId,并且想要找到喜欢该用户且该用户也喜欢他的其他用户:

    using (var context = new Context())
    {
        // For a given user id = 1
        var friends = (from u in context.Users
                       where u.UserId == 1
                       from v in u.LikeThisUser
                       where v.UserId == u.ThisUserLikesId
                       select new 
                       { 
                           OurUser = u, 
                           HerFriend = v 
                       })
                       .SingleOrDefault();
    
        ExchangeContactInfo(friends.OurUser, friends.HerFriend);
    }                
    


    更新 1:

    自引用多对多关联将使用连接表映射到数据库,这需要完全不同的对象模型和流畅的 API:

    public class User
    {
        public int UserId { get; set; }
        public string Name { get; set; }
    
        public virtual ICollection<User> ThisUserLikes { get; set; }
        public virtual ICollection<User> UsersLikeThisUser { get; set; }
    }
    
    public class Context : DbContext
    {
        public DbSet<User> Users { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                        .HasMany(u => u.ThisUserLikes)
                        .WithMany(u => u.UsersLikeThisUser)
                        .Map(c => 
                        {
                            c.MapLeftKey("UserId");
                            c.MapRightKey("OtherUserId");
                            c.ToTable("UserLikes");
                        });
        }
    }
    


    更新 2:

    正如我在 this post 中解释的那样,多对多关联不能有有效负载(例如 EventId),如果是这种情况,那么我们必须将其分解为两个一对多关联以进行干预类,我可以看到你已经正确地创建了这个类(UserLike)来表示附加到你的自引用多对多关联的额外信息,但是这个中间类的关联不正确,因为我们需要精确定义 2 many从 UserLike 到 User 的一对一关联,就像我在以下对象模型中展示的那样:

    public class User
    {        
        public int UserId { get; set; }
        public string Email { get; set; }       
    
        public virtual ICollection ThisUserLikes { get; set; }
        public virtual ICollection UsersLikeThisUser { get; set; }
    }       
    
    public class UserLike
    {
        public int UserLikeId { get; set; }
        public int LikerId { get; set; }
        public int LikeeId { get; set; }
        public int EventId { get; set; }
    
        public User Liker { get; set; }
        public User Likee { get; set; }
        public virtual Event Event { get; set; }
    }
    
    public class Event
    {
        public int EventId { get; set; }
        public string Name { get; set; }
    }  
    
    public class Context : DbContext 
    {
        public DbSet Users { get; set; } 
        public DbSet Events { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity()
                        .HasMany(u => u.ThisUserLikes)
                        .WithRequired(ul => ul.Liker)
                        .HasForeignKey(ul => ul.LikerId);
            modelBuilder.Entity()                        
                        .HasMany(u => u.UsersLikeThisUser)
                        .WithRequired(ul => ul.Likee)
                        .HasForeignKey(ul => ul.LikeeId)
                        .WillCascadeOnDelete(false);
        }
    }
    

    现在您可以使用以下 LINQ 查询来检索所有互相喜欢的用户:

    using (var context = new Context())
    {                
        var friends = (from u1 in context.Users
                       from likers in u1.UsersLikeThisUser
                       from u2 in u1.ThisUserLikes 
                       where u2.LikeeId == likers.LikerId
                       select new
                       {
                           OurUser = u1.UserId,
                           HerFriend = u2.LikeeId 
                       })
                       .ToList();
    }
    

    希望这会有所帮助。

    【讨论】:

    • Morteza,感谢您的快速回复......这太棒了......现在,假设一个用户可以喜欢很多用户并且很多用户可以喜欢这个用户,这将如何改变?
    • 最后一个问题......他们彼此喜欢什么活动。如何在联结表中添加另一列 eventId?
    • 请查看更新 2,我在其中向您提出了最后一个问题。
    • Update 2 给了我这个错误:'CollectionCollectionBuilder' 不包含'Map' 的定义并且没有可访问的扩展方法'Map' 接受'CollectionCollectionBuilder'(您是否缺少 using 指令或程序集引用?)...有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 2012-10-20
    • 2011-08-13
    • 2013-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多