I will send you a sample project with a possible implementation of this scenario. Please check that the letter is not blocked by your mail filter.
Suppose we have the following entity class (we do not set the Timestamp attribute on the version property):
Code: Select all
public class Concur {
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public long Id { get; set; }
[MaxLength(32)]
public string Title { get; set; }
public Byte[] Timestamp { get; set; }
}
Declare an interim DbContext descendant:
Code: Select all
public class MyDbContext : DbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
//modelBuilder.Conventions.Remove<System.Data.Entity.Infrastructure.IncludeMetadataConvention>();
}
public DbSet Concurs { get; set; }
}
We will then inherit two context classes, one for each DBMS, from the MyDbContext class:
Code: Select all
public class MySqlContext : MyDbContext {
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Concur>().Property(p => p.Timestamp)
.IsRowVersion();
}
}
public class MyOracleContext : MyDbContext {
public MyOracleContext(): base() {
((IObjectContextAdapter)this).ObjectContext.SavingChanges += new EventHandler(ObjectContext_SavingChanges);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Concur>().Property(p => p.Timestamp)
.HasMaxLength(16)
.IsConcurrencyToken();
modelBuilder.Conventions.Remove();
}
static void ObjectContext_SavingChanges(object sender, EventArgs e) {
ObjectContext context = (ObjectContext)sender;
var addedOrModified = context.ObjectStateManager
.GetObjectStateEntries(EntityState.Added | EntityState.Modified)
.Where(entry => entry.Entity is Concur)
.Select(entry => (Concur)entry.Entity)
.ToList();
foreach (Concur item in addedOrModified) {
item.Timestamp = Guid.NewGuid().ToByteArray();
}
context.DetectChanges();
}
}
Notice that the MySqlContext class relies on the server functionality, whereas MyOracleContext needs to create new GUIDs on its own at the client side.
The following code shows the possible scenario where a concurrency exception is thrown:
Code: Select all
Concur newCon = new Concur { Title = "Original" };
context.Concurs.Add(newCon);
context.SaveChanges(); // Inserted successfully
var originalItem = anotherContext.Concurs
.Where(c => c.Title == "Original")
.Single();
originalItem.Title = "First modification";
anotherContext.SaveChanges(); // Updated successfully
try {
newCon.Title = "Second modification";
context.SaveChanges(); // DbUpdateConcurrencyException thrown
}
catch (DbUpdateConcurrencyException ex) {
Console.WriteLine(ex.Message);
}
Please tell us if this helps.