在一长串计算中,我该如何避免“实体类型'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已经紧紧抓住和跟踪。

+0

我一直在尝试你列出的第二种方法,但据我所知,它标记任何对象的嵌套集合中的人作为“添加”的变化跟踪器,它会导致各种问题,当它尝试保存。我尝试使用AutoMapper.Collection来解决这个问题,但我无法让它在dot net core中工作。 – LayfieldK