ABP Framework 6.0父子实体处理最佳实践及跟踪错误解决咨询
父子实体场景下ABP Framework 6.0的跟踪冲突问题及最佳实践咨询
项目概述
近期基于ABP Framework 6.0开发,创建了DemoApp项目用于复现问题。
领域层实体
Company.cs
public class Company : FullAuditedAggregateRoot<Guid> { public virtual string Code { get; set; } public virtual string Name { get; set; } public virtual ICollection<Site> Sites { get; set; } }
Site.cs
public class Site : AuditedEntity<Guid> { protected Site() { } public Site(Guid id) : base(id) { } public virtual Guid CompanyId { get; set; } public virtual Company Company { get; set; } public virtual string Code { get; set; } public virtual string Name { get; set; } }
注:原Site类继承
FullAuditedEntity<Guid>,后改为AuditedEntity<Guid>
应用契约层DTO
- CompanyDto.cs
- CreateCompanyDto.cs
- UpdateCompanyDto.cs
- SiteOfCompanyDto.cs(关联CompanyDto)
- SiteOfCreateCompanyDto.cs(关联CreateCompanyDto)
- SiteOfUpdateCompanyDto.cs(关联UpdateCompanyDto)
应用层服务实现
public class CompanyService : ApplicationService, ICompanyService { private readonly ICompanyRepository _companyRepository; public CompanyService(ICompanyRepository companyRepository) { _companyRepository = companyRepository; } public async Task<CompanyDto> CreateAsync(CreateCompanyDto input) { var entity = ObjectMapper.Map<CreateCompanyDto, Company>(input); entity = await _companyRepository.InsertAsync(entity); return ObjectMapper.Map<Company, CompanyDto>(entity); } public async Task<IEnumerable<CompanyDto>> CreateCompaniesAsync(IEnumerable<CreateCompanyDto> input) { var entities = ObjectMapper.Map<IEnumerable<CreateCompanyDto>, IEnumerable<Company>>(input); await _companyRepository.InsertManyAsync(entities); return ObjectMapper.Map<IEnumerable<Company>, IEnumerable<CompanyDto>>(entities); } public async Task DeleteAsync(Guid id) { await _companyRepository.DeleteAsync(id); } public async Task<IEnumerable<CompanyDto>> GetAllAsync() { var entities = await _companyRepository.GetListAsync(includeDetails: true); return ObjectMapper.Map<IEnumerable<Company>, IEnumerable<CompanyDto>>(entities); } public async Task<CompanyDto> GetAsync(Guid id) { var entity = await _companyRepository.GetAsync(id, includeDetails: true); return ObjectMapper.Map<Company, CompanyDto>(entity); } public async Task<CompanyDto> GetByCodeAsync(string code) { var entity = await _companyRepository.GetAsync(o => o.Code == code, includeDetails: true); return ObjectMapper.Map<Company, CompanyDto>(entity); } public async Task<CompanyDto> UpdateAsync(Guid id, UpdateCompanyDto input) { var entity = await _companyRepository.GetAsync(id, includeDetails: true); entity = ObjectMapper.Map(input, entity); entity = await _companyRepository.UpdateAsync(entity); return ObjectMapper.Map<Company, CompanyDto>(entity); } public async Task<IEnumerable<CompanyDto>> UpdateCompaniesAsync(IDictionary<Guid, UpdateCompanyDto> input) { var entities = await _companyRepository.GetListAsync(o => input.Keys.Contains(o.Id)); entities = ObjectMapper.Map(input.Values, entities); await _companyRepository.UpdateManyAsync(entities); return ObjectMapper.Map<IEnumerable<Company>, IEnumerable<CompanyDto>>(entities); } }
问题现象
执行测试时抛出以下错误:
System.InvalidOperationException : The instance of entity type 'Site' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
将Site类改为继承AuditedEntity<Guid>后,仅Should_Update_Company测试通过,Should_Create_Company、Should_Create_Companies及Should_Update_Companies测试仍报相同错误。
查阅ABP官方文档及相关Issue后,仍不明确父子实体场景下服务类与DTO类的最佳编写方式,特此咨询。
内容的提问来源于stack exchange,提问作者Kalves
相关产品推荐
相关产品推荐

