我收到以下错误:
<块引用>无法跟踪实体类型“公司”的实例,因为已跟踪另一个具有键值“{Id: 1}”的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。'
这是我的背景:
public class Context: DbContext
{
public Context(DbContextOptions<Context> options) : base(options)
{
this.ChangeTracker.LazyLoadingEnabled = false;
}
public DbSet<Company> Companies { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
Seed.OnModelCreating(builder);
//builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
存储库基础
public class EfRepository<T> : IAsyncRepository<T> where T : class
{
protected readonly Context_context;
public EfRepository(Context dbContext)
{
_context = dbContext;
}
public virtual T GetById(int id)
{
var keyValues = new object[] { id };
return _context.Set<T>().Find(keyValues);
}
public List<T> List(Expression<Func<T, bool>> filter = null)
{
return filter != null ? _context.Set<T>().Where(filter).ToList() : _context.Set<T>().ToList();
}
public int Count(Expression<Func<T, bool>> filter = null)
{
return filter != null ? _context.Set<T>().Where(filter).Count() : _context.Set<T>().Count();
}
public void Add(T entity)
{
_context.Set<T>().Add(entity);
_context.SaveChanges();
}
public void Update(T entity)
{
var model = _context.Entry(entity);
model.State = EntityState.Modified;
_context.SaveChanges();
}
public void Delete(T entity)
{
_context.Set<T>().Remove(entity);
_context.SaveChanges();
}
public IQueryable<T> GetQueryable(Expression<Func<T, bool>> filter = null)
{
return filter == null
? _context.Set<T>()
: _context.Set<T>().Where(filter);
}
public T Get(Expression<Func<T, bool>> filter = null)
{
return filter == null
? _context.Set<T>().FirstOrDefault()
: _context.Set<T>().FirstOrDefault(filter);
}
public T GetWithoutTracking(Expression<Func<T, bool>> filter = null)
{
return filter == null
? _context.Set<T>().AsNoTracking().FirstOrDefault()
: _context.Set<T>().AsNoTracking().FirstOrDefault(filter);
}
public EntityState GetEntityState(T entity)
{
return _context.Entry(entity).State;
}
}
public class CompanyRepository : EfRepository<Company>, ICompanyRepository
{
public CompanyRepository(Context dbContext) : base(dbContext)
{}
public IQueryable<CompanyDtoWithDetail> GetCompanyWithDetail(int? id = null)
{
return (from company in _context.Companies
join companyType in _context.Definitions on company.CompanyTypeId equals companyType.Id
join country in _context.Countries on company.CountryId equals country.Id
join city in _context.Cities on company.CityId equals city.Id
join district in _context.Districts on company.DistrictId equals district.Id
join customerGroup in _context.Definitions on company.CustomerGroupId equals customerGroup.Id
where id.HasValue ? company.Id == id : true
select new CompanyDtoWithDetail(company, _context.AuthorizedPersons.OrderBy(person => person.Id).FirstOrDefault(person => person.CompanyId == company.Id), companyType.Name, country.Name, city.Name, district.Name, customerGroup.Name)
);
}
}
业务层更新方法
[ValidationAspect(typeof(CompanyValidator), Priority = 1)]
public IDataResult<Company> Update(Company entity)
{
var check = _companyRepository.GetWithoutTracking(x => x.Id == entity.Id);
if (check == null)
return new ErrorDataResult<Company>(Messages.CompanyNotFound);
_companyRepository.Update(entity);
var result = _companyRepository.GetCompanyWithDetail(entity.Id).FirstOrDefault();
return new SuccessDataResult<Company>(result, Messages.CompanyUpdated);
}
API 控制器
[HttpPut("update")]
public IActionResult Update(Company company)
{
var result = _companyService.Update(company);
return StatusCode(result.GetStatusCode(), result);
}
Startup.cs
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
// Auto Mapper Configurations
services.AddSingleton(new MapperConfiguration(mc =>
{
mc.AddProfile(new AutoMapperBusinessProfile());
}).CreateMapper());
services.AddDbContext<Context>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("Context"));
options.EnableSensitiveDataLogging(true);
}
);
services.AddDependencyResolvers(new ICoreModule[]
{
new CoreModule(),
});
public class CompanyDtoWithDetail : Company
{
public string CompanyTypeName { get; set; }
public string CountryName { get; set; }
public string CityName { get; set; }
public string DistrictName { get; set; }
public string CustomerGroupName { get; set; }
public AuthorizedPerson AuthorizedPerson { get; set; }
public CompanyDtoWithDetail(Company company, AuthorizedPerson authorizedPerson, string companyTypeName, string countryName, string cityName, string districtName, string customerGroupName)
{
this.Id = company.Id;
this.CompanyTypeId = company.CompanyTypeId;
this.CompanyTypeName = companyTypeName;
this.Code = company.Code;
this.CommercialTitle = company.CommercialTitle;
this.Explanation = company.Explanation;
this.CountryId = company.CountryId;
this.CountryName = countryName;
this.CityId = company.CityId;
this.CityName = cityName;
this.DistrictId = company.DistrictId;
this.DistrictName = districtName;
this.Address = company.Address;
this.ZipCode = company.ZipCode;
this.CustomerGroupId = company.CustomerGroupId;
this.CustomerGroupName = customerGroupName;
this.IsInBlackList = company.IsInBlackList;
this.AuthorizedPerson = authorizedPerson;
}
}
[ValidationAspect(typeof(CompanyValidator), Priority = 1)]
public IDataResult<CompanyDtoWithDetail> Update(Company entity)
{
var check = _companyRepository.GetWithoutTracking(x => x.Id == entity.Id);
if (check == null)
return new ErrorDataResult<CompanyDtoWithDetail>(Messages.CompanyNotFound);
var entityState1 = _companyRepository.GetEntityState(entity); //Detached
_companyRepository.Update(entity);
var entityState2 = _companyRepository.GetEntityState(entity); // Unchanged
var result = _companyRepository.GetCompanyWithDetail(entity.Id).FirstOrDefault();
var entityState4 = _companyRepository.GetEntityState((Company)result); //Detached
return new SuccessDataResult<CompanyDtoWithDetail>(result, Messages.CompanyUpdated);
}
答案 0 :(得分:0)
您的实体状态在您调用时更改为已修改,然后是未更改
_companyRepository.Update(entity);
在此处查看带注释的实现:
public void Update(T entity)
{
var model = _context.Entry(entity);
// state is now Modified. This supercedes the AsNoTracking()
model.State = EntityState.Modified;
_context.SaveChanges();
// state is now Unchanged here; it's now part of the tracking
}
然后当你打电话
var result = _companyRepository.GetCompanyWithDetail(entity.Id).FirstOrDefault();
您收到该错误是因为您试图将另一个实体(同一个)加载到上下文中,其中一个实体已存在且具有上述 未更改 状态。
更新后,您需要先分离实体(将其状态设置为分离)
context.Entry(entity).State = EntityState.Detached;
或者您需要完全使用新的上下文。如何将其放入通用存储库取决于您。实际上,您没有遵循典型的工作单元模式 (source):
<块引用>使用 Entity Framework Core (EF Core) 时的典型工作单元涉及(我的重点已添加):
当您在 DbContext
之后使用 SaveChanges
时,上下文仍然是“活动的”,因为它的当前状态仍然是活动的;如果您执行了与当前状态不兼容的操作,例如尝试再次加载同一实体,则会出现错误。
使用 DbContextFactory
上面引用的来源建议您use a DbContext factory 当您的工作范围与 DbContext 生命周期不一致时。您的案例符合条件,因为您在 SaveChanges
之后工作。
资源
总而言之,您有 3 个选择