Anto
Anto
CC#
Created by Anto on 6/16/2023 in #help
❔ [EF.Core] Discard external relations updates during concurrency conflicts
Hello, I'm in a situation where I have to handle a concurrency conflict inside an asp.net Core application using Npgsql. I'm using the generic approach suggested by Microsoft (more info here https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=data-annotations#resolving-concurrency-conflicts) and handling a DbUpdateConcurrencyException. My DB is made of just 2 tables. A Payments one
public class Payment
{
public string Id { get; set; }
public int Amount { get; set; }
public List<PaymentNotification> Notifications { get; set; }
public uint Version { get; set; }
}
public class Payment
{
public string Id { get; set; }
public int Amount { get; set; }
public List<PaymentNotification> Notifications { get; set; }
public uint Version { get; set; }
}
And a PaymentNotifications one
public class PaymentNotification
{
public string Id { get; set; }
public string Name { get; set; }
}
public class PaymentNotification
{
public string Id { get; set; }
public string Name { get; set; }
}
Whenever there's a conflict detected, and the proposed payment entity is carrying new Notifications , I want to keep the the new Amount but discard the latest Notifications:
...
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is not Payment) continue;

// take the Amount already stored in the DB
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
var proposedValue = proposedValues[nameof(Payment.Amount)];
var databaseValue = databaseValues[nameof(Payment.Amount)];
proposedValues[nameof(Payment.Amount)] = databaseValue;

// TODO: discard any eventual proposednotifications
var proposedNotif = entry.Collection(nameof(Payment.Notifications)).CurrentValue;

// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);

}
}
...
...
catch (DbUpdateConcurrencyException ex)
{
foreach (var entry in ex.Entries)
{
if (entry.Entity is not Payment) continue;

// take the Amount already stored in the DB
var proposedValues = entry.CurrentValues;
var databaseValues = entry.GetDatabaseValues();
var proposedValue = proposedValues[nameof(Payment.Amount)];
var databaseValue = databaseValues[nameof(Payment.Amount)];
proposedValues[nameof(Payment.Amount)] = databaseValue;

// TODO: discard any eventual proposednotifications
var proposedNotif = entry.Collection(nameof(Payment.Notifications)).CurrentValue;

// Refresh original values to bypass next concurrency check
entry.OriginalValues.SetValues(databaseValues);

}
}
...
I can't find a way to persist the notifications that are already in the database. In the end, I find all the notifications from both the concurrent saves. Can you help me with that?
2 replies