我试图实现一个让用户喜欢评论的功能。如果用户已经喜欢它,则不能再次喜欢它,反之亦然。 这是它的样子:
public async Task<ActionResult<CommentResponse>> LikeComment(LikeComment like)
{
if (like.HasNullProperty())
return BadRequest("Missing properties!");
var comment = await commentService.GetCommentWithLikes((int) like.CommentId);
if(comment is null)
return NotFound($"No comment with id {like.CommentId} was found");
try
{
var userId = User.GetUserID();
comment = await commentService.LikeComment(comment, userId, (bool)like.Liked);
return comment is not null ? Ok(comment.GetCommentResponse((bool)like.Liked)) : StatusCode(304);
}
catch(Exception e)
{
return StatusCode(500, $"Error while trying to {((bool)like.Liked ? "like" : "dislike")} comment");
}
}
相关功能:
public async Task<Comment> GetCommentWithLikes(int id) => await blogContext.Comments.IncludeLikes().FirstOrDefaultAsync(x => x.Id == id);
public static IQueryable<Comment> IncludeLikes(this IQueryable<Comment> source)
=> source.Select(x => new Comment
{
Id = x.Id,
ArticleId = x.ArticleId,
CreatedById = x.CreatedById,
CreatedAt = x.CreatedAt,
Likes = x.LikedBy.Count,
Text = x.Text,
});
还有主要的逻辑:
public async Task<Comment> LikeComment(Comment comment, string userId, bool liked)
{
var user = new User { Id = userId };
var hasLiked = await blogContext.Comments.Where(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id)).FirstOrDefaultAsync() is not null;
Action action = null;
if (!hasLiked && liked)
{
action = () => comment.LikedBy.Add(user);
comment.LikedBy = new List<User>();
comment.Likes++;
}
else if (hasLiked && !liked)
{
action = () => comment.LikedBy.Remove(user);
comment.LikedBy = new List<User> { user };
comment.Likes--;
}
if (action is null)
return null;
blogContext.Attach(user);
blogContext.Attach(comment);
action();
await blogContext.SaveChangesAsync();
return comment;
}
我们的想法是不加载整个 likeBy 关系,但仍通知 EF Core 我已添加或删除了一个用户。因此,我修改了评论,然后附加它,以便 EF Core 跟踪对 likeBy 关系的更改。有趣的是,它在喜欢评论时工作正常。但是,当不喜欢时,我收到一条错误消息,表明该评论已附加。在 GetCommentsWithLikes 函数中使用 .AsNoTracking() 没有帮助。
<块引用>无法跟踪实体类型“Comment”的实例,因为已经跟踪了另一个具有相同 {'Id'} 键值的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。
也许有人知道这种行为的原因,可以帮助我或建议不同的方法:) 谢谢
答案 0 :(得分:2)
在 GetCommentsWithLikes 函数中使用 .AsNoTracking() 没有帮助
由于使用了投影,该函数已经隐式没有跟踪。这是下面的电话
var hasLiked = await blogContext.Comments
.Where(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id))
.FirstOrDefaultAsync() is not null;
当结果不为空时,它会向更改跟踪器添加一个 Comment
实例。
由于您不需要该实例并且只是检查是否存在,请改用以下不涉及实体实例的纯服务器端查询:
var hasLiked = await blogContext.Comments
.AnyAsync(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id));