I'm having an EF Core DbUpdateConcurrencyException issue. I've got this Widget object, and it has a list of Package objects. When I try to update the Widget and add some new Packages to its list, I keep getting this DbUpdateConcurrencyException.
Here's the gist of my code:
public async Task<RequestResponse> Handle(UpdateWidgetCommand request, CancellationToken cancellationToken)
{
// ... validation ...
var package = new Package
{
PackageName = "New Package",
// ... other properties ...
Packages = [new()
{
PackageName = "Sub Package",
// ... other properties ...
}]
};
var success = await _repository.UpdateWidget(request.WidgetId, request.PackageId, package);
if (success)
{
await _repository.SaveChangesAsync();
return new RequestResponse(OperationState.Success());
}
else
{
return new RequestResponse(OperationState.Failed("Failed to update Widget"));
}
}
public async Task<bool> UpdateWidget(Guid widgetId, Guid packageId, Package package)
{
var widget = await _context.Widgets
.Include(w => w.Packages)
.Include(w => w.Components)
.SingleOrDefaultAsync(w => w.Id == widgetId);
var existingPackage = widget.Packages.SingleOrDefault(p => p.Id == packageId);
// Changing properties on an existing Package works fine
existingPackage.PackageName = package.PackageName;
existingPackage.ModifiedDate = DateTime.Now;
// This line blows up with a concurrency exception
existingPackage.Packages.AddRange(package.Packages);
// But this line, updating existing entries in another list, works fine
widget.Components.ForEach(x => x.IsInstalled = false);
return true;
}
Basically:
Widget has a list of Packages and another list called Components.Widget and its lists.Package in the Packages list which works.Packages to the existingPackage.Packages list using AddRangeI get the Concurrency error.Components list and change stuff, and that works.I get that the concurrency error means something's changed in the database since I loaded the Widget, but I don't get why it's only happening when I add to the Packages list.
So, my questions are:
Packages list cause a problem, but changing properties on an existing Package and looping through Components doesn't?Packages without getting this error?TIA
It looks like (from the validation code) a package contains child packages, but when a widget is loaded from context, those child objects possibly aren't being included (and so won't be tracked).
If a package contains child packages I'd expect something like (note the ThenInclude to include the child package references):
var widget = await _context.Widgets
.Include(w => w.Packages).ThenInclude(p => p.Packages)
.Include(w => w.Components)
.SingleOrDefaultAsync(w => w.Id == widgetId);
Although to me it's not clear from the above what the Primary Key for the entities are, so if you (for example) have something like PackageId, ParentPackageId defined.
One other thing you could try is seeing what the change tracking debugging shows : https://learn.microsoft.com/en-gb/ef/core/change-tracking/debug-views
The exception that you are showing happens when the change tracker cannot detect changes (which is why I suggested looking at the child packages within the object model), the debug view may show this (or otherwise why it thinks there are no changes). See here for more details on the exception : https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.infrastructure.dbupdateconcurrencyexception?view=entity-framework-6.2.0
Hope this helps - if you could post more details about the entity relationships it may help people understand the issue, but from the above I suspect the issue is related to load including the child packages.
Probably it doesn't quite clear hierarchy for EF by adding a chain of packages this way.
Try to extend the Package entity by int? ParentPackageId property and set the hierarchy first by traversing each object in the package argument.
Then the collection of packages should be saved using the package repository.
The parent package should be added to the widget object and saved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With