Closed ScottKane closed 2 years ago
Most minimal repro I can show: https://github.com/ScottKane/SetValues
Set Server
as startup project
Update DB
Run
Add a Customer
, It will the appear in the table. Click the edit icon and try to change FirstName
or LastName
, it will work, then try updating House Number
, Street
or Email
which wont work. Observe each of the handlers under Server\Handlers to debug and see behaviour
Also I'm aware that using a UnitOfWork/Repository pattern with EF is redundant, but the bigger application this comes from allows switching ORM's as well as the application layer calling the repository has no knowledge of the DbContext and that is why it's being used
@ScottKane There's a lot of code here, but as far as I can tell there is nothing that actually updates the dependent entities. I think it might be worth reading through Explicitly Tracking Entities to understand how EF Core change tracking works with graphs of entities.
Get this entity with the given Id, set its values to that of this given object e.g:
DB has this representation of Person
public class Person
{
public int Id{ get; set; } = 1
public string Name { get; set; } = "Bob"
}
var selected = await _dbContext.Set<Person>().FindAsync(entity.Id);
if (selected is not null) // Got Bob
{
_dbContext.Entry(selected).CurrentValues.SetValues(
new Person
{
Id = 1,
Name = "John"
});
await _dbContext.SaveChangesAsync();
}
The value for Person
with an Id
of 1
should now return "John"
and not "Bob"
, which it does.
However if we take the following example:
public class Person
{
public int Id{ get; set; } = 1
public string Name { get; set; } = "Bob"
public Address Address { get; set; } = new Address { Street = "Drury Lane" };
}
public class Address
{
public string Street { get; set; }
}
var selected = await _dbContext.Set<Person>().FindAsync(entity.Id);
if (selected is not null) // Got Bob
{
_dbContext.Entry(selected).CurrentValues.SetValues(
new Person
{
Id = selected.Id,
Name = selected.Name,
Address = new Address { Street = "Abbey Road" }
});
await _dbContext.SaveChangesAsync();
}
The entity would still have and Address.Street
of "Drury Lane"
and not "Abbey Road"
as expected.
So I can just use context.Update()
instead? That's fine but I'm still fairly sure this is a bug.
Update doesn't work, it thinks I'm trying to add a new entity:
System.InvalidOperationException: The instance of entity type 'Customer' cannot be tracked because another instance with the same key value for {'Id'} is already b
eing tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSe
nsitiveDataLogging' to see the conflicting key values.
_dbContext.Entry(selected).CurrentValues.SetValues()
works fine until I need to update a nested object.
I think this may be because the mapper bringing in the DTO and mapping to a Customer is missing some of the DB fields, forcing the mapped DTO (now a Customer) to re-map that customer to the selected customer seems to work.
@ScottKane SetValues
works on a single entity instance. It does not set values for related entity instances.
@ajcvickers well I'm using it to do that and it definitely is updating the related entity. I'm assuming this is because a Customer
owns an Address
so it's effectively treaded as part of the entity? I'm never using this to update a one to many relationship as there is a separate API for the child entity to be updated.
https://github.com/dotnet/efcore/issues/14626#issuecomment-461883036 https://stackoverflow.com/questions/11705569/using-the-entrytentity-currentvalues-setvalues-is-not-updating-collections Workaround to manually fill navigation props: https://stackoverflow.com/questions/66206459/update-navigation-property-with-entity-currentvalues-setvalues/66491805#66491805
I have the following methods on a repository:
I have the following entity:
DB context configures the following behaviour for
Customer
:Calling
AddAsync
successfully adds the entity to the DB, callingUpdateAsync
will update only the top level non nested properties.When I try to update the entity with a new
Address
orContact
, the values aren't updated. But if I updateFirstName
it works fine. Should this be working as I expect or am I missing something?Provider and version information
EF Core version: 6.0.7 Database provider: Microsoft.EntityFrameworkCore.SqlServer Target framework: .NET 6.0 Operating system: Windows 11 IDE: 2022.1.2