【问题标题】:Problem with relations beetwen entity models实体模型之间的关系问题
【发布时间】:2019-02-11 15:53:55
【问题描述】:

我想在我的项目中创建一个喜欢和不喜欢系统, 我有一个用户模型,一个帖子模型,一个评论模型,关系如下:

用户 1 ---> * 发布

用户 1 ---> * 评论

发布 1 ---> * 评论

现在我想添加一个名为 Like 的新模型,其关系如下:

发布 1 ---> * 喜欢 用户 1 ---> * 喜欢

但是当我想更新数据库时,我收到一条错误消息: “可能导致循环或多个级联路径” 我发现如果我删除我的一个属性,它会修复错误, 例如:

public class Post
{

    public Post()
    {

    }

    [Key]
    public int Id { get; set; }

    public string Title { get; set; }

    public virtual List<Like> Likes { get; set; }

    public virtual List<Comment> Comments { get; set; }

}



public class Like
{

    public Like()
    {

    }

    [Key]
    public int Id { get; set; }

    public bool IsLike { get; set; }


    public int postId { get; set; } // I remove these properties

    public virtual Post post { get; set; }


    public int commentId { get; set; }  // I remove these properties

    public virtual Comment comment { get; set; }

}

为了修复“多级联”错误,我删除了“PostId”和“commentId”属性。

但是当我将实体(新数据)添加到数据库中的表(喜欢)时, 我不知道我的帖子是如何被重复的,我的意思是重复的帖子被添加到表格中。

谁能告诉我这个问题?

【问题讨论】:

  • 检查我更新的答案。我又做了一些改动。
  • 您应该显示复制帖子的代码。我敢打赌这是this infamous pitfall 的另一个实例。

标签: c# asp.net-mvc entity-framework-6 ef-code-first


【解决方案1】:

为了更好的设计,将PostComment 的like 表分开如下:

public class User
{
    [Key]
    public int Id { get; set; }

    //......

    public virtual List<Post> Posts { get; set; }

    public virtual List<Comment> Comments { get; set; }

    public virtual List<PostLikes> PostLikes { get; set; }

    public virtual List<CommentLIkes> CommentLikes { get; set; }
}


public class Post
{
    [Key]
    public int Id { get; set; }

    public string Title { get; set; }

    public virtual List<PostLike> PostLikes { get; set; }

    public virtual List<Comment> Comments { get; set; }
}

public class Comment
{
    [Key]
    public int Id { get; set; }

    public string CommentBody { get; set; }

    //.....

    public virtual List<CommentLike> CommentLikes { get; set; }
}

public class PostLike
{
    [Key]
    public int Id { get; set; }

    public int PostId { get; set; }

    public int UserId {get; set;}

    public bool IsLike { get; set; }

    public virtual Post post { get; set; }
    public virtual User User { get; set; }
}

public class CommentLike
{
    [Key]
    public int Id { get; set; }

    public int CommentId { get; set; }

    public int UserId {get; set;}

    public bool IsLike { get; set; }

    public virtual Comment Comment { get; set; }
    public virtual User User { get; set; }

}

现在生成一个全新的迁移并相应地更新数据库。

注意:迁移更新时您可能会遇到级联删除问题。如果您面对,请告诉我,我将使用 Fluent API 配置更新答案。

【讨论】:

  • 首先,感谢您的回复,但我没有得到您的某些代码的原因,例如为什么您在模型中重复了“IsLike”属性?如果我们有一个单独的“Like”模型不是更好吗?
  • 是的!如果您只有 like 选项,则可以省略 IsLike 属性。如果您有不喜欢选项,则保留此属性以指示 false 表示不喜欢。
【解决方案2】:

问题是,您的数据库还不够规范化。

我看到用户可以创建Posts。他们也可以在PostCommentLike cmets。

由于CommentComment about a Post,因此Comment 上的Like 自动成为评论所针对的Post 上的Like

换句话说:如果有人为帖子 (10) 创建了评论 (4),那么为评论 (4) 和帖子 (20) 创建一个赞是荒谬的。评论(4)与帖子(20)无关!

每个赞都是由一个用户针对一个评论创建的。用户创建了零个或多个赞(一对多),并且评论被赞了零次或多次(也是一对多)

所以你有以下动作序列:

  • 用户 1 创建帖子 10:帖子 10 具有外键 CreateByUserId 1
  • 用户 2 创建关于帖子 10 的评论 20。评论 20 具有 CommentedByUserId 2 和 PostId 20
  • 用户 3 赞了评论 20。赞 30 有 LikedByUserId 3 和 CommentId 20

这对于实体框架来说已经足够标准化了。为了使关系更清晰,我稍微更改了外键。

class User
{
     public int Id {get; set;}
     ...

     // Every User creates zero or more Posts (one-to-many)
     public virtual ICollection<Post> Posts {get; set;}

     // Every User creates zero or more Comments (one-to-many)
     public virtual ICollection<Comment> Comments {get; set;}

     // Every User creates zero or more Likes (one-to-many)
     public virtual ICollection<Like> Likes {get; set;}
}

class Post
{
    public int Id {get; set;}
    ...

    // Every Post is posted by exactly one User, using foreign key
    public int PostedByUserId {get; set;}
    public User User {get; set;}

    // Every Post has zero or more Comments (one-to-many)
    public virtual ICollection<Comment> Comments {get; set;}
}

和类评论和喜欢:

class Comment
{
    public int Id {get; set;}
    ...

    // Every Comment is posted by exactly one User, using foreign key
    public int CommentedByUserId {get; set;}
    public virtual User User {get; set;}

    // Every Comment is about exactly one Post, using foreign key
    public int PostId {get; set;}
    public virtual Post Post {get; set;}

    // Every Comment has zero or more Likes (one-to-many)
    public virtual ICollection<Like> Likes {get; set;}
}
class Like
{
    public int Id {get; set;}
    ...

    // Every Like is created by exactly one User, using foreign key
    public int LikedByUserId {get; set;}
    public virtual User User {get; set;}

    // Every Like is about exactly one Comment, using foreign key
    public int CommentId {get; set;}
    public virtual Comment Comment {get; set;}
}

因为我的外键偏离了约定,我需要使用 fluent API 通知实体框架这些外键:

帖子对用户有外键:

modelBuilder.Entity<Post>()
    .HasRequired(post => post.User)
    .WithMany(user => user.Posts)
    .HasForeignKey(post => post.CreatedByUserId);

评论有用户和帖子的外键:

var commentEntity = modelBuilder.Entity<Comment>();
commentEntity.HasRequired(comment => comment.User)
    .WithMany(user => user.Comments)
    .HasForeignKey(comment => comment.CommentedByUserId);
commentEntity.HasRequired(comment => comment.Post)
    .WithMany(post => post.Comments)
    .HasForeignKey(comment => comment.PostId);

Like 对 User 和 Comment 有外键:

var likeEntity = modelBuilder.Entity<Like>();
likeEntity.HasRequired(like => like.User)
    .WithMany(user => user.Likes)
    .HasForeignKey(like => like.LikedByUserId);
likeEntity.HasRequired(like  => like.Comment)
    .WithMany(comment => comment.Likes)
    .HasForeignKey(like => like.CommentId);

如果将来您想让用户喜欢帖子而不是评论,或者可能喜欢用户,则关系将非常相似。首先为用户提供正确的virtual ICollection&lt;...&gt;(每个用户都喜欢零个或多个...),您将自动知道将外键放在哪里

【讨论】:

  • 我认为你没有明白这一点,我希望用户能够喜欢帖子而不是 cmets。
  • 在这种情况下,您的情况非常相似:用户有零个或多个喜欢的帖子的集合,每个帖子都被零个或多个用户点赞。一个like 对喜欢它的用户有一个外键,对被喜欢的帖子有一个外键。我以为你会自己弄清楚
猜你喜欢
  • 2016-09-17
  • 2013-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多