99 lines
3.5 KiB
C#
99 lines
3.5 KiB
C#
using System;
|
|
using System.ComponentModel.DataAnnotations;
|
|
using System.Linq;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace EFSaving.Concurrency
|
|
{
|
|
public class Sample
|
|
{
|
|
public static void Run()
|
|
{
|
|
// Ensure database is created and has a person in it
|
|
using (var setupContext = new PersonContext())
|
|
{
|
|
setupContext.Database.EnsureDeleted();
|
|
setupContext.Database.EnsureCreated();
|
|
|
|
setupContext.People.Add(new Person { FirstName = "John", LastName = "Doe" });
|
|
setupContext.SaveChanges();
|
|
}
|
|
|
|
#region ConcurrencyHandlingCode
|
|
using var context = new PersonContext();
|
|
// Fetch a person from database and change phone number
|
|
var person = context.People.Single(p => p.PersonId == 1);
|
|
person.PhoneNumber = "555-555-5555";
|
|
|
|
// Change the person's name in the database to simulate a concurrency conflict
|
|
context.Database.ExecuteSqlRaw(
|
|
"UPDATE dbo.People SET FirstName = 'Jane' WHERE PersonId = 1");
|
|
|
|
var saved = false;
|
|
while (!saved)
|
|
{
|
|
try
|
|
{
|
|
// Attempt to save changes to the database
|
|
context.SaveChanges();
|
|
saved = true;
|
|
}
|
|
catch (DbUpdateConcurrencyException ex)
|
|
{
|
|
foreach (var entry in ex.Entries)
|
|
{
|
|
if (entry.Entity is Person)
|
|
{
|
|
var proposedValues = entry.CurrentValues;
|
|
var databaseValues = entry.GetDatabaseValues();
|
|
|
|
foreach (var property in proposedValues.Properties)
|
|
{
|
|
var proposedValue = proposedValues[property];
|
|
var databaseValue = databaseValues[property];
|
|
|
|
// TODO: decide which value should be written to database
|
|
// proposedValues[property] = <value to be saved>;
|
|
}
|
|
|
|
// Refresh original values to bypass next concurrency check
|
|
entry.OriginalValues.SetValues(databaseValues);
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException(
|
|
"Don't know how to handle concurrency conflicts for "
|
|
+ entry.Metadata.Name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
|
|
public class PersonContext : DbContext
|
|
{
|
|
public DbSet<Person> People { get; set; }
|
|
|
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
|
{
|
|
// Requires NuGet package Microsoft.EntityFrameworkCore.SqlServer
|
|
optionsBuilder.UseSqlServer(
|
|
@"Server=(localdb)\mssqllocaldb;Database=EFSaving.Concurrency;Trusted_Connection=True");
|
|
}
|
|
}
|
|
|
|
public class Person
|
|
{
|
|
public int PersonId { get; set; }
|
|
|
|
[ConcurrencyCheck]
|
|
public string FirstName { get; set; }
|
|
|
|
[ConcurrencyCheck]
|
|
public string LastName { get; set; }
|
|
|
|
public string PhoneNumber { get; set; }
|
|
}
|
|
}
|
|
} |