新增项目懒加载失效:非代理类异常问题排查与解决咨询
问题描述
维护项目时添加仓库,从数据库获取所有项目数据时,除最后新增的项目外,其余项目均以Castle.Proxies.ProjectProxy形式存在。已配置UseLazyLoadingProxies()并将实体属性标记为virtual启用懒加载,但最新创建的项目无法触发懒加载。
相关代码示例
添加并获取项目的逻辑:
var addedProject = await _projectRepository.AddAsync(projectToAdd); await _projectRepository.SaveAsync(); var userProjects = await _projectRepository.GetAllAsync()
项目仓库实现:
public class ProjectRepository : Repository<Project>, IProjectRepository { public ProjectRepository(TeamHubDbContext TeamHubDbContext) : base(TeamHubDbContext) { } }
通用仓库抽象类:
public abstract class Repository<TEntity> : IRepository<TEntity> where TEntity : class, new() { protected readonly TeamHubDbContext TeamHubDbContext; protected Repository(TeamHubDbContext socialNetworkContext) { TeamHubDbContext = socialNetworkContext; } public virtual async Task<List<TEntity>> GetAllAsync() { return await TeamHubDbContext.Set<TEntity>().ToListAsync(); } public async Task<TEntity> AddAsync(TEntity entity) { return (await TeamHubDbContext.AddAsync(entity)).Entity; } public virtual async Task SaveAsync() { await TeamHubDbContext.SaveChangesAsync(); } }
DbContext实现:
public partial class TeamHubDbContext : DbContext { public DbSet<Project> Projects { get; set; } public TeamHubDbContext(DbContextOptions options) : base(options) { Database.EnsureCreated(); } protected override void OnModelCreating(ModelBuilder builder) { builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly()); } }
问题成因
- 新增实体未被代理包装:调用
AddAsync添加的是手动创建的原始实体对象,EF Core不会自动为其生成代理,即使保存到数据库,当前上下文中的该实体依然是原始类型,而非代理类型。 - 上下文缓存优先加载:调用
GetAllAsync时,EF Core会先从ChangeTracker(上下文缓存)中读取已存在的实体。新增的项目因为是缓存中的原始对象,直接被返回;而数据库中已存在的项目是从数据库加载时生成的代理对象,所以显示为Castle.Proxies.ProjectProxy。
解决办法
方法1:保存后重新获取实体
保存后通过主键重新从数据库获取新增项目,确保拿到代理对象:
var addedProject = await _projectRepository.AddAsync(projectToAdd); await _projectRepository.SaveAsync(); // 假设仓库有根据ID获取的方法 addedProject = await _projectRepository.GetByIdAsync(addedProject.Id); var userProjects = await _projectRepository.GetAllAsync();
方法2:用上下文创建代理实体
直接通过EF Core的CreateProxy方法生成代理对象再填充属性,从根源保证实体是代理类型:
// 依赖注入获取TeamHubDbContext实例 var projectToAdd = _teamHubDbContext.CreateProxy<Project>(); // 填充项目属性 projectToAdd.Name = "新项目"; projectToAdd.Description = "项目描述"; var addedProject = await _projectRepository.AddAsync(projectToAdd); await _projectRepository.SaveAsync(); var userProjects = await _projectRepository.GetAllAsync();
方法3:修改AddAsync方法生成代理
在通用仓库的AddAsync方法中,检查并自动为原始实体生成代理:
public async Task<TEntity> AddAsync(TEntity entity) { // 判断当前实体是否为代理对象 if (!TeamHubDbContext.Entry(entity).IsProxy) { // 创建代理实例 var proxyEntity = TeamHubDbContext.CreateProxy<TEntity>(); // 复制原始实体的属性值到代理对象 TeamHubDbContext.Entry(proxyEntity).CurrentValues.SetValues(entity); entity = proxyEntity; } return (await TeamHubDbContext.AddAsync(entity)).Entity; }
方法4:清空上下文缓存(不推荐)
如果不需要保留上下文的追踪状态,可以在获取所有项目前清空ChangeTracker,强制从数据库加载所有代理对象:
var addedProject = await _projectRepository.AddAsync(projectToAdd); await _projectRepository.SaveAsync(); // 清空上下文所有追踪的实体 TeamHubDbContext.ChangeTracker.Clear(); var userProjects = await _projectRepository.GetAllAsync();
内容的提问来源于stack exchange,提问作者Nazar Masukov
相关产品推荐
相关产品推荐

