I am a newbie to EF and am struggling to do what seems like a basic update. I have read numerous posts on similar issues. From what I gather this is not currently easy to do in EF Core 2.1 and requires a complex workaround. Is this actually possible or should I simply update the child entities directly and individually?
Note: if I just update the exampleA and do not include the child entities it works fine.
I get the following error:
An unhandled exception occurred while processing the request. InvalidOperationException: The instance of entity type 'ExampleB' 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. Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap.ThrowIdentityConflict(InternalEntityEntry entry)
Stack Query Cookies Headers InvalidOperationException: The instance of entity type 'ExampleB' 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.
I have created a basic example of the issue. First stackoverflow post also so let me know if more info is required.
Any help would be greatly appreciated.
WebAPI controller:
[HttpPut]
public async Task<ActionResult> UpdateExample(ExampleADto exampleADto)
{
var exampleAFromDB = await _context.ExampleA.Include(x => x.ExampleBs).Where(x => x.Id == exampleADto.Id).SingleOrDefaultAsync();
if (exampleAFromDB == null)
return NotFound();
_mapper.Map(exampleADto, exampleAFromDB);
if (await _context.SaveChangesAsync() > 0)
return Ok(exampleAFromDB);
throw new Exception("Failed to update ExampleA");
}
exampleA in DB before update:
{
"id": 1,
"description": "Example A1",
"exampleBDtos": [
{
"id": 1,
"description": "B1",
"someNumber": 1
},
{
"id": 2,
"description": "B2",
"someNumber": 2
},
{
"id": 3,
"description": "B3",
"someNumber": 3
}
]
}
exampleADto:
{
"id": 1,
"description": "Example A1 Updated",
"exampleBDtos": [
{
"id": 1,
"description": "B1 Updated",
"someNumber": 1
},
{
"id": 2,
"description": "B2",
"someNumber": 2
},
{
"id": 3,
"description": "B3",
"someNumber": 3
}
]
}
exampleA after Automapping:
{
"id": 1,
"description": "Example A1 Updated",
"exampleBDtos": [
{
"id": 1,
"description": "B1 Updated",
"someNumber": 1
},
{
"id": 2,
"description": "B2",
"someNumber": 2
},
{
"id": 3,
"description": "B3",
"someNumber": 3
}
]
}
exampleA in DB after failed update (no change):
{
"id": 1,
"description": "Example A1",
"exampleBDtos": [
{
"id": 1,
"description": "B1",
"someNumber": 1
},
{
"id": 2,
"description": "B2",
"someNumber": 2
},
{
"id": 3,
"description": "B3",
"someNumber": 3
}
]
}
AutoMapper Profiles:
public AutoMapperProfiles()
{
CreateMap<ExampleA, ExampleADto>()
.ForMember(x => x.ExampleBDtos, opt => opt.MapFrom(x => x.ExampleBs));
CreateMap<ExampleB, ExampleBDto>();
CreateMap<ExampleADto, ExampleA>()
.ForMember(x => x.ExampleBs, opt => opt.MapFrom(x => x.ExampleBDtos));
CreateMap<ExampleBDto, ExampleB>();
}
Update 1: Added object after automapping
Update 2: It seems Automapper does not map collections without dropping and recreating the items which messes with EF.
AutoMapper.Collection https://www.nuget.org/packages/AutoMapper.Collection/ does not currently work with EF Core so I have simply created a function myself to manually map and update the collection.