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; }
 | |
|         }
 | |
|     }
 | |
| } |