[英]EF Core - Modify realations without loading entity
我试图实现一个 function 让用户喜欢评论。 如果用户已经点赞,则不能再点赞,反之亦然。 这是它的样子:
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 function 中使用.AsNoTracking() 没有帮助。
无法跟踪实体类型“评论”的实例,因为已经在跟踪另一个具有相同 {'Id'} 键值的实例。 附加现有实体时,请确保仅附加一个具有给定键值的实体实例。 考虑使用“DbContextOptionsBuilder.EnableSensitiveDataLogging”来查看冲突的键值。
也许有人知道这种行为的原因,可以帮助我或提出不同的方法:) 谢谢
在 GetCommentsWithLikes function 中使用.AsNoTracking() 没有帮助
由于使用了投影,function 已经隐式没有跟踪。 这是以下调用
var hasLiked = await blogContext.Comments
.Where(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id))
.FirstOrDefaultAsync() is not null;
当结果不是 null 时,将向更改跟踪器添加Comment
实例。
由于您不需要该实例并且只是检查是否存在,因此请改用以下不涉及实体实例,而是纯粹的服务器端查询:
var hasLiked = await blogContext.Comments
.AnyAsync(x => x.Id == comment.Id && x.LikedBy.Any(x => x.Id == user.Id));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.