添加新Review后Company的Reviews列表未更新且导航属性为null
问题排查:新增Review后Company的Reviews列表未更新且导航属性为null
实体类代码
Company类
public class Company { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int CompanyId { get; } // 注意:此处仅含getter,EF可能无法正确跟踪实体状态 [MaxLength(100)] public string CompanyName { get; set; } = string.Empty; [MaxLength(500)] public string CompanyDescription { get; set; } = string.Empty; [MaxLength(100)] public string Location { get; set; } = string.Empty; [MaxLength(50)] public string City { get; set; } = string.Empty; [MaxLength(50)] public string Category { get; set; } = string.Empty; [MaxLength(400)] public string PhotoUrl { get; set; } public List<Review> Reviews { get; set; } = new List<Review>(); }
Review类
public class Review { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ReviewId { get; set; } [Required,MaxLength(70)] public string JobTitle { get; set; } = string.Empty; [Required, MaxLength(1000)] public string Content { get; set; } = string.Empty; public DateTime TimeCreated { get; set; } = DateTime.UtcNow; public int TotalUpvotes { get; set; } = 0; public ApplicationUser User { get; set; } public string UserId { get; set; } public Company Company { get; set; } public int CompanyId { get; set; } }
OnModelCreating配置
Company表配置
builder.HasKey(c => c.CompanyId); builder.HasMany(c=>c.Reviews) .WithOne(c => c.Company) .HasForeignKey(c => c.CompanyId);
Review表配置
builder.HasKey(r => r.ReviewId); builder.HasOne(r=>r.User) .WithMany(r=>r.Reviews) .HasForeignKey(r=>r.UserId) .OnDelete(DeleteBehavior.ClientCascade); builder.HasOne(r => r.Company) .WithMany(r => r.Reviews) .HasForeignKey(r => r.CompanyId) .OnDelete(DeleteBehavior.ClientCascade);
新增Review的服务代码
public async Task<ServiceResponse<AddReviewResponseDto>> AddReview(AddReviewDto addReviewDto) { ServiceResponse<AddReviewResponseDto> AddReviewResponse = new ServiceResponse<AddReviewResponseDto>(); // 检查当前用户是否已注册 var user = await _userManager.FindByIdAsync(GetUserId()); if (user == null) { AddReviewResponse.Data = null; AddReviewResponse.Success = false; AddReviewResponse.Message = "未注册用户无法添加评论!"; return AddReviewResponse; } // 拼写错误:CompnayId 应为 CompanyId var company = await _context.Companies.SingleOrDefaultAsync(c => c.CompanyId == addReviewDto.CompnayId); if (company == null) { AddReviewResponse.Data = null; AddReviewResponse.Success = false; AddReviewResponse.Message = "未找到对应ID的公司!"; return AddReviewResponse; } var review = new Review { JobTitle = addReviewDto.JobTitle, Content = addReviewDto.Content, User = user, Company = company }; await _context.AddAsync(review); company.Reviews.Add(review); await _context.SaveChangesAsync(); var addReviewResponseDto = new AddReviewResponseDto { TimeCreated = review.TimeCreated, ReviewId = review.ReviewId }; AddReviewResponse.Data = addReviewResponseDto; AddReviewResponse.Success = true; AddReviewResponse.Message = "评论添加成功"; return AddReviewResponse; }
接口返回结果
Review返回数据
"reviewId": 14, "jobTitle": "software engineer", "content": "I Love This Company", "timeCreated": "2023-03-23T18:54:04.7119397", "totalUpvotes": 0, "user": null, "userId": "userIdvalue", "company": null, "companyId": 6, "upvotes": []
Company返回数据
{ "companyId": 6, "companyName": "Globe Exports", "companyDescription": "We Globe exportsare exporters of canned products, pasta, flour, biscuits, jams, honey, tahina, halawa, foul, tomato puree, biscuits, wafer,spices&bean.", "location": "Cairo, Egypt", "city": "Cairo", "category": "Food Industries", "photoUrl": "photoUrl", "reviewsCount": 0, "averageRating": 0, "reviews": [] }
问题排查与解决方案
1. 实体类主键限制问题
Company类的CompanyId仅包含get方法,无set。EF Core需要实体主键具备可访问的setter(私有setter也可)才能正确跟踪实体状态,否则无法将数据库生成的ID赋值给实体,进而影响关联关系维护。
修复:给CompanyId添加私有setter:
[DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int CompanyId { get; private set; }
2. 服务代码拼写错误
查询公司时使用了addReviewDto.CompnayId,正确应为addReviewDto.CompanyId。虽当前Review成功插入了CompanyId=6,但该错误会导致其他场景下无法匹配公司,必须修正。
3. 导航属性未显式加载
返回的Review中company为null、Company中reviews为空,原因是查询时未显式包含导航属性。EF Core默认不会自动加载关联数据(延迟加载在API序列化时易失效)。
修复:
- 查询Company时加载关联的Reviews:
var company = await _context.Companies .Include(c => c.Reviews) .SingleOrDefaultAsync(c => c.CompanyId == addReviewDto.CompanyId);
- 若需返回带Company的Review数据,查询Review时也需Include:
var review = await _context.Reviews .Include(r => r.Company) .FirstOrDefaultAsync(r => r.ReviewId == reviewId);
4. 关联关系维护简化
代码中同时执行_context.AddAsync(review)和company.Reviews.Add(review)虽可行,但可简化为直接设置外键,EF会自动维护反向关联:
var review = new Review { JobTitle = addReviewDto.JobTitle, Content = addReviewDto.Content, UserId = user.Id, CompanyId = company.CompanyId }; await _context.AddAsync(review); await _context.SaveChangesAsync();
此方式无需手动添加到company.Reviews,EF会自动同步(上下文需处于跟踪状态)。
内容的提问来源于stack exchange,提问作者Alaa
相关产品推荐
相关产品推荐

