c# - mvc - Concurrencia optimista con Entity Framework y MySQL
entity framework discriminator (2)
Gran advertencia: NO PROBADO , solo pensando en voz alta.
EF admite la anulación de SaveChanges
, por lo que quizás una opción sea definir una interfaz como:
interface IVersionedRow {
int RowVersion {get;set;}
}
y agregue una propiedad / campo int RowVersion
a su (s) clase (s) de modelo y a la (s) tabla (s) de base de datos, y use partial class
para implementar esta interfaz (usando implementación de interfaz implícita):
partial class Customer : IVersionedRow {}
partial class Order : IVersionedRow {}
...
Luego anule SaveChanges
, algo así como:
public override int SaveChanges(SaveOptions options)
{
foreach (ObjectStateEntry entry in
ObjectStateManager.GetObjectStateEntries(EntityState.Modified))
{
var v = entry.Entity as IVersionedRow;
if(v != null) v.RowVersion++;
}
return base.SaveChanges(options);
}
que luego debería funcionar (en teoría, no probado) como un contador de versión de fila implementado manualmente. Deje la validación de cambio habilitada para RowVersion
, y eso debería servir.
Actualmente estoy desarrollando una aplicación que usa Entity Framework 4.1 y MySQL. Quiero utilizar la concurrencia optimista y, por lo tanto, necesito crear una estructura de tabla que permita a EF detectar problemas de concurrencia. Mi objetivo es algo similar a esto: http://blogs.msdn.com/b/alexj/archive/2009/05/20/tip-19-how-to-use-optimistic-concurrency-in-the-entity- framework.aspx .
Mi problema es que el tipo de marca de tiempo es diferente en MySQL comparado con MS SQL Server. Además de eso, ni timestamp ni datetime ofrecen una precisión de menos de segundo en MySQL (http://feedblog.org/2007/05/26/why-doesnt-mysql-support-millisecond-datetime-resolution/). Por lo tanto, estos tipos serían bastante malos para detectar problemas de simultaneidad.
¿Qué otro tipo de datos podría usar para resolver esto? Estaba pensando en tal vez usar un Guid. Sin embargo, hay dos posibles problemas con este enfoque: 1. MySQL almacena Guids como char (36), lo que los hace muy ineficientes. 2. No estoy seguro si el EF requiere que la versión de la fila aumente estrictamente o si es suficiente que sea única.
Esta es una solución probada (para EF6 y superior).
Aquí lo que tienes que hacer en tu modelo:
[Table("some_table")]
public class SomeEntity : IVersionedRow //define an interface as described previously and replace int type to long
{
...
[Column("row_version")]
public long RowVersion { get; set; }
}
Entonces en tu contexto:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<SomeEntity>()
.Property(p => p.RowVersion).IsConcurrencyToken();
base.OnModelCreating(modelBuilder);
}
public override int SaveChanges()
{
var objectContextAdapter = this as IObjectContextAdapter;
if (objectContextAdapter != null) {
objectContextAdapter.ObjectContext.DetectChanges();
foreach (ObjectStateEntry entry in objectContextAdapter.ObjectContext.ObjectStateManager.GetObjectStateEntries(EntityState.Modified)) {
var v = entry.Entity as IVersionedRow;
if (v != null)
v.RowVersion++;
}
}
return base.SaveChanges();
}
Ahora cuando actualice o elimine la operación, no olvide incluir DbUpdateConcurrencyException . Funciona perfecto para mi