I have the following method:
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
var accounts = await _context.Accounts.ToListAsync();
var currentAccountIndex = accounts.FindIndex(x => x.Id == request.Id);
var currentAccount = accounts[currentAccountIndex];
var previousAccount = accounts[currentAccountIndex - 1];
accounts[currentAccountIndex] = previousAccount;
accounts[currentAccountIndex - 1] = currentAccount;
bool changesDetected = _context.ChangeTracker.HasChanges();
await _context.SaveChangesAsync();
return Unit.Value;
}
I save in memory a list of accounts from the database using EF, then I swap two elements in that list and want to apply the changes back to the database. What you see above is the happy path, no error or out of bounds checking.
However entity framework seems to believe that no changes occured as changesDetected
is false
. Is there a way to explicitly tell EF that there are some changes that I want to be saved?
CodePudding user response:
What would change in the database, when you store the list back? Has any of the elements of the list, any of the "entities" really changed? Would any data in any row in the database change?
Think about it: How was the order of elements determined in first place when you ToList'ed them?
If you analyze that problem properly, you will notice that what you tried to do has no sense.
If you want to control the order of the items, then you have to control it, not believe that something does it. Define sorting criteria to get predictable ordering. Then, when you want to permanently change the order of the items, modify the underlying data (the data the criteria check during sorting), and that's it.
CodePudding user response:
According your code, there are nothing change on the Entity.
If you want to force EF to update database, you can call Update
method, force EF to update everything of the entity even there are no changes.
the sample code as below:
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
....
_context.Accounts.Update(currentAccount);
_context.Accounts.Update(previousAccount);
// now the changesDetected will be true
bool changesDetected = _context.ChangeTracker.HasChanges();
await _context.SaveChangesAsync();
....
}
CodePudding user response:
You can make sure the EF saves the changes by attaching the modified entities and marking them as modified as shown in the code below:
public async Task<Unit> Handle(Command request, CancellationToken cancellationToken)
{
var accounts = await _context.Accounts.ToListAsync();
var currentAccountIndex = accounts.FindIndex(x => x.Id == request.Id);
var currentAccount = accounts[currentAccountIndex];
var previousAccount = accounts[currentAccountIndex - 1];
accounts[currentAccountIndex] = previousAccount;
accounts[currentAccountIndex - 1] = currentAccount;
// attach the modified entities to the context
_context.Accounts.Attach(previousAccount);
_context.Accounts.Attach(currentAccount);
// mark the modified entities as modified
_context.Entry(previousAccount).State = EntityState.Modified;
_context.Entry(currentAccount).State = EntityState.Modified;
await _context.SaveChangesAsync();
return Unit.Value;
}