在一长串计算中,我该如何避免“实体类型'Person'的实例无法跟踪......”
我正在开发一个控制台应用程序,该应用程序将执行由一组复杂业务组成的单个事务逻辑。在此事务中会调用多个服务,并且几乎可以肯定的是,任何给定的实体都将在存储库中多次更新。在一长串计算中,我该如何避免“实体类型'Person'的实例无法跟踪......”
我正在使用依赖注入来注入我的存储库,服务,dbcontext和工作单元,无论他们需要什么。在很早的阶段,交易看起来是这样的:
using (var scope = serviceProvider.CreateScope())
{
var dbContext = scope.ServiceProvider
.GetRequiredService<FantasySimulationDBContext>();
using (var dbContextTransaction =
dbContext.Database.BeginTransaction())
{
try
{
var flowControllerService =
scope.ServiceProvider.GetService<IFlowControllerService>();
flowControllerService.IncrementTime();
flowControllerService.IncrementTime();
dbContextTransaction.Commit();
}
catch (Exception e)
{
dbContextTransaction.Rollback();
}
}
}
我只能叫flowControllerService.IncrementTime()两次来说明我想拥有的功能类型。我希望这是一种可能性,现在不是。
在我服务的IncrementTime方法是这样的:
public void IncrementTime()
{
//do a bunch of stuff to a "Person" object
_personRepository.UpdatePerson(person);
_unitOfWork.Complete();
}
的PersonRepository映射我的域模型回持久性模型,并在更新的DbContext他们。它看起来像这样:
public class PersonRepository: IPersonRepository
{
private readonly FantasySimulationDBContext _dbContext;
private IMapper _mapper;
public PersonRepository(FantasySimulationDBContext context, IMapper mapper)
{
_dbContext = context;
_mapper = mapper;
}
...
public void UpdatePerson(Person person)
{
var mappedPerson = _mapper.Map<PersistenceModels.Person>(person);
_dbContext.People.Update(mappedPerson);
}
}
什么最终发生的是第一次调用IncrementTime工作正常。但是,第二次调用会导致发生以下异常:“实体类型'Person'的实例无法跟踪,因为具有相同键的此类型的另一个实例已被跟踪。”我知道这是因为当我第一次保存时,我保存的“Person”仍然在dbContext的changetracker中,然后在第二次调用IncrementTime时重新使用相同的dbContext。因此,当人员储存库尝试第二次更新同一个人时,我会收到异常,因为它已经在更改跟踪器中。
我可以在每次提交工作单元后分离所有内容,但是我从来没有在其他人的代码中看到过,所以我假设我的整个过程的某些基本方面是错误的。那么处理这个问题的正确方法是什么呢?或者说,我在设计这个方面有什么失误?
基本上有两种方法可以做到这一点从我可以告诉(除了你说的方式:分离等)。首先,您可以坚持实体并更新它,而不是您正在使用的“DTO”。其他将是获取Person
这样的实例:
var personModel = _dbContext.People.Find(person.ID);
_mapper.Map(person, personModel);
_dbContext.SaveChanges();
你总是只使用单一实例的方式,你DBContext
已经紧紧抓住和跟踪。
我一直在尝试你列出的第二种方法,但据我所知,它标记任何对象的嵌套集合中的人作为“添加”的变化跟踪器,它会导致各种问题,当它尝试保存。我尝试使用AutoMapper.Collection来解决这个问题,但我无法让它在dot net core中工作。 – LayfieldK