Code first Entity Framework - 对 Comment 功能进行评论,相同的评论出现两次
Code first Entity Framework - Comment on a Comment feature, same comment shows up on twice
我正在开发评论功能。您可以对线程发表评论。你也可以评论评论。所以线程有一个评论列表,每个评论都有一个评论列表:
public class Thread
{
public int ThreadId { get; set; }
public int PostId { get; set; }
public virtual List<Comment> Comments { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
[MaxLength(280)]
public string Content { get; set; }
public long time { get; set; } // unix time / epoch time
[JsonIgnore]
[IgnoreDataMember]
public string user_id { get; set; }
public virtual CommentUser CommentUser { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public int ThreadId { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual Thread Thread { get; set; }
public virtual List<Comment> Comments { get; set; }
}
我遇到的问题是,当我评论一个话题然后评论那个评论时。所以一共有两条评论。
我收到这个 JSON,有三个评论:
{
"ThreadId": 3,
"Comments": [
{
"Comments": [
{
"Comments": [],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 52,
"Content": "comment on comment",
"time": 1513784459
}
],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 51,
"Content": "asdf asdf asd f",
"time": 1513784447
},
{
// THIS COMMENT SHOULD NOT SHOW UP HERE
"Comments": [],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 52,
"Content": "comment on comment",
"time": 1513784459
}
]
}
这是数据库的样子,只有两条评论:
获取线程的方法很简单:
Thread commentThread = await (from t in db.Thread where t.PostId == tr.postId select t).FirstOrDefaultAsync();
return Json(commentThread);
我很难找出哪里出了问题。任何帮助表示赞赏!
正如@Ivan 和@Olivier 在他们的评论中提到的那样,发生这种情况是因为 Comment
实体与所有者 Thread
有直接关系(必需),与级别无关。
基本上,当您执行 linq 查询时,结果是带有两个 Comments
的 Thread
对象。第二个是您可以在第一条评论中看到的相同评论。哦,男孩,这是一口。
像这样:
commentThread.Comments = Comment[]
//first comment from thread
{
"CommentId": 1,
"Content": "Thread comment",
"Comments": [
//This is the same comment (Id = 2) being fetched from both Thread and Comment entities.
{
"CommentId": 2,
"Content": "Comment on comment"
}
]
},
//second comment from thread
{
"CommentId": 2,
"Content": "Comment on comment"
}
]
避免此问题的一种方法是仅引用顶级评论中的线程,并在所有嵌套评论中将 ThreadId 设置为 null。这将为您提供最佳结果,因为您的查询将保持干净(即您不需要更改代码来过滤或排除,也不需要检查是否引用了评论)。
但是您当前的模型不允许这样做,因为您的 ThreadId 是 int
。根据您向我们展示了多少模型,这应该相对容易完成。所以只需将 属性 ThreadId
设置为 int?
:
public class Comment
{
public int CommentId { get; set; }
[MaxLength(280)]
public string Content { get; set; }
public long time { get; set; } // unix time / epoch time
[JsonIgnore]
[IgnoreDataMember]
public string user_id { get; set; }
public virtual CommentUser CommentUser { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public int? ThreadId { get; set; }
^ //set this as nullable
[JsonIgnore]
[IgnoreDataMember]
public virtual Thread Thread { get; set; }
public virtual List<Comment> Comments { get; set; }
}
运行 迁移并更新您的数据库(或为您的 DBA 获取脚本):
add-migration SetThreadIdAsNullable
update-database OR update-database -script
你应该可以开始了。查询现在应该 return thread
对象只有一个 comment
,而后者又应该包含一个嵌套的 comment
,如您所愿。
希望对您有所帮助!
这是Thread
实体的惯常行为。因为,在评论table中有两条记录ThreadId = 3
。所以,应该剔除Comment_CommentId
不为空的评论记录。所以,也许你可以用扩展方法过滤它;
public static class ThreadExtensions
{
public static IQueryable<Thread> GetThreadAsQueryable(this DbSet<Thread> table)
{
return table.Where(x => x.Comments.Where(x => x.Comment_CommentId == null));
}
}
using (var context = new SampleDbContext())
{
var str = context.Thread.GetThreadAsQueryable().ToList();
}
此外,EfCore 2.0 有一个名为 HasQueryFilter
的功能。我想,它正是满足了那个需要。如果你使用 EfCore 2.0,我建议你检查 it。
我正在开发评论功能。您可以对线程发表评论。你也可以评论评论。所以线程有一个评论列表,每个评论都有一个评论列表:
public class Thread
{
public int ThreadId { get; set; }
public int PostId { get; set; }
public virtual List<Comment> Comments { get; set; }
}
public class Comment
{
public int CommentId { get; set; }
[MaxLength(280)]
public string Content { get; set; }
public long time { get; set; } // unix time / epoch time
[JsonIgnore]
[IgnoreDataMember]
public string user_id { get; set; }
public virtual CommentUser CommentUser { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public int ThreadId { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public virtual Thread Thread { get; set; }
public virtual List<Comment> Comments { get; set; }
}
我遇到的问题是,当我评论一个话题然后评论那个评论时。所以一共有两条评论。
我收到这个 JSON,有三个评论:
{
"ThreadId": 3,
"Comments": [
{
"Comments": [
{
"Comments": [],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 52,
"Content": "comment on comment",
"time": 1513784459
}
],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 51,
"Content": "asdf asdf asd f",
"time": 1513784447
},
{
// THIS COMMENT SHOULD NOT SHOW UP HERE
"Comments": [],
"CommentUser": {
"user_id": "123",
"nickname": "user",
},
"CommentId": 52,
"Content": "comment on comment",
"time": 1513784459
}
]
}
这是数据库的样子,只有两条评论:
获取线程的方法很简单:
Thread commentThread = await (from t in db.Thread where t.PostId == tr.postId select t).FirstOrDefaultAsync();
return Json(commentThread);
我很难找出哪里出了问题。任何帮助表示赞赏!
正如@Ivan 和@Olivier 在他们的评论中提到的那样,发生这种情况是因为 Comment
实体与所有者 Thread
有直接关系(必需),与级别无关。
基本上,当您执行 linq 查询时,结果是带有两个 Comments
的 Thread
对象。第二个是您可以在第一条评论中看到的相同评论。哦,男孩,这是一口。
像这样:
commentThread.Comments = Comment[]
//first comment from thread
{
"CommentId": 1,
"Content": "Thread comment",
"Comments": [
//This is the same comment (Id = 2) being fetched from both Thread and Comment entities.
{
"CommentId": 2,
"Content": "Comment on comment"
}
]
},
//second comment from thread
{
"CommentId": 2,
"Content": "Comment on comment"
}
]
避免此问题的一种方法是仅引用顶级评论中的线程,并在所有嵌套评论中将 ThreadId 设置为 null。这将为您提供最佳结果,因为您的查询将保持干净(即您不需要更改代码来过滤或排除,也不需要检查是否引用了评论)。
但是您当前的模型不允许这样做,因为您的 ThreadId 是 int
。根据您向我们展示了多少模型,这应该相对容易完成。所以只需将 属性 ThreadId
设置为 int?
:
public class Comment
{
public int CommentId { get; set; }
[MaxLength(280)]
public string Content { get; set; }
public long time { get; set; } // unix time / epoch time
[JsonIgnore]
[IgnoreDataMember]
public string user_id { get; set; }
public virtual CommentUser CommentUser { get; set; }
[JsonIgnore]
[IgnoreDataMember]
public int? ThreadId { get; set; }
^ //set this as nullable
[JsonIgnore]
[IgnoreDataMember]
public virtual Thread Thread { get; set; }
public virtual List<Comment> Comments { get; set; }
}
运行 迁移并更新您的数据库(或为您的 DBA 获取脚本):
add-migration SetThreadIdAsNullable
update-database OR update-database -script
你应该可以开始了。查询现在应该 return thread
对象只有一个 comment
,而后者又应该包含一个嵌套的 comment
,如您所愿。
希望对您有所帮助!
这是Thread
实体的惯常行为。因为,在评论table中有两条记录ThreadId = 3
。所以,应该剔除Comment_CommentId
不为空的评论记录。所以,也许你可以用扩展方法过滤它;
public static class ThreadExtensions
{
public static IQueryable<Thread> GetThreadAsQueryable(this DbSet<Thread> table)
{
return table.Where(x => x.Comments.Where(x => x.Comment_CommentId == null));
}
}
using (var context = new SampleDbContext())
{
var str = context.Thread.GetThreadAsQueryable().ToList();
}
此外,EfCore 2.0 有一个名为 HasQueryFilter
的功能。我想,它正是满足了那个需要。如果你使用 EfCore 2.0,我建议你检查 it。