2012-10-04 4 views
10

EF no tiene control de concurrencia (la última escritura gana) lo que permite la pérdida de actualizaciones. La aplicación de comprobaciones de concurrencia optimistas se puede configurar explícitamente configurando ConcurrencyMode = Fixed en una columna RowVersion.Cómo automatizar la configuración ConcurrencyMode = Solucionado en todas las columnas RowVersion?

¿Cómo podemos automatizar la configuración de ConcurrencyMode = Solucionado en columnas RowVersion en todas las tablas? Teniendo que hacer esto manualmente al volver a crear un modelo EF desde una base de datos, corremos el riesgo de olvidarlo como una ejecución sin control de concurrencia.

+1

Un XSLT en su proceso de construcción? –

+1

Esperaba algo incorporado que se me escapara, tal vez algo por convención. Este es un requisito estándar. La mayoría de las aplicaciones de DB requieren control de concurrencia. –

+1

No entiendo por qué esa característica básica no existe. Realizado una solicitud de función en EF CodePlex [Configuración de automatización ConcurrencyMode = Fixed] (http://entityframework.codeplex.com/workitem/588) –

Respuesta

6

Esto es similar a la respuesta de Mohamed Cassim, pero he actualizado el código para utilizar XML atributo de búsqueda y reemplazo, en lugar de cadena de reemplazo, ya que el diseñador puede cambiar el orden de los atributos, u otras propiedades puede tener diferentes valores

Guárdelo como FixVersionColumnConcurrencyMode.cs, ejecute csc FixVersionColumnConcurrencyMode.cs y ejecute FixVersionColumnConcurrencyMode.exe resultante en la misma carpeta que el archivo .edmx. También puede hacerlo ejecutar la construcción posterior del proyecto.

using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Xml.Linq; 

namespace Utility 
{ 
    internal class FixVersionColumnConcurrencyMode 
    { 
     private static void Main(string[] args) 
     { 
      string directoryPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); 
      var files = Directory.GetFiles(directoryPath, "*.edmx"); 
      foreach (var file in files) 
      { 
       XDocument xmlDoc = XDocument.Load(file); 

       IEnumerable<XElement> versionColumns = 
        from el in xmlDoc.Descendants() 
        where (string)el.Attribute("Name") == "Version" 
        && (string)el.Attribute("Type") == "Binary" 
        && (string)el.Attribute("ConcurrencyMode") != "Fixed" 
        select el; 
       bool modified = false; 
       foreach (XElement el in versionColumns) 
       { 
        modified = true; 
        el.SetAttributeValue("ConcurrencyMode", "Fixed"); 
       } 
       if (modified) 
        xmlDoc.Save(file); 
      } 
     } 
    } 
} 
+0

Considere cambiar la primera cláusula where a 'donde el.Attribute ("Nombre")! = Null && el.Attribute ("Nombre"). Value.Contains ("rowversion")' para cubrir un espectro más amplio de nombres de columnas –

1

No lo he hecho yo mismo (aún, pero probablemente deba hacerlo pronto), pero debería ser posible cambiar la herramienta utilizada para generar código desde .edmx.

Here es un artículo que lo explica para VS2008. Supongo que el proceso será similar para VS2010 y VS2012.

No estoy seguro, sin embargo, si esto hará posible perder el modo ConcurrencyMode de alguna manera.

4

En EF6, el diseñador configurará ConcurrencyMode = Fijo en las columnas de conversión de filas al crear un modelo desde la base de datos. Consulte Designer: Automate setting ConcurrencyMode=Fixed on rowversion columns. Hasta entonces tendremos que hacer esto manualmente.

+1

Desafortunadamente, la última publicación de estado de RoMiller fue "Solo estamos realizando cambios mínimos en el diseñador en EF6 porque todavía estamos convirtiendo la base de código en código abierto. considere este error para la próxima versión ". – Rick

4

parece que esta característica no va a estar allí por 5 EF o EF 6.

Azoté una rápida aplicación de consola para actualizar la base de datos después de generar edmx Primera.

Simplemente coloque el archivo en el mismo directorio de su archivo edmx y ejecútelo después de cada regeneración.

funcionará para cualquiera de las siguientes columnas:

RowVersion timestamp NOT NULL 
rowversion timestamp NOT NULL 
RowVer  timestamp NOT NULL 
rowver  timestamp NOT NULL 

usted puede conseguir la aplicación de consola aquí https://dl.dropbox.com/u/3576345/EFConcurrencyFixed.exe

o utilizar este pedazo de código en su propia aplicación de consola.

class Program 
{ 
    static Dictionary<string, string> replacements = new Dictionary<string, string>() 
    { 
     { "<Property Type=\"Binary\" Name=\"RowVersion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Type=\"Binary\" Name=\"RowVersion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Type=\"Binary\" Name=\"rowversion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Type=\"Binary\" Name=\"rowversion\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Type=\"Binary\" Name=\"RowVer\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Type=\"Binary\" Name=\"RowVer\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Type=\"Binary\" Name=\"rowver\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Type=\"Binary\" Name=\"rowver\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 
    }; 

    static void Main(string[] args) 
    { 
     // find all .edmx 
     string directoryPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 
     foreach (var file in Directory.GetFiles(directoryPath)) 
     { 
      // only edmx 
      if (!file.EndsWith(".edmx")) 
       continue; 

      // read file 
      var fileContents = System.IO.File.ReadAllText(file); 

      // replace lines 
      foreach (var item in replacements) 
       fileContents = fileContents.Replace(item.Key, item.Value); 

      // overwite file 
      System.IO.File.WriteAllText(file, fileContents); 
     } 
    } 
} 
1

Cuando haya añadido ConcurrencyMode=Fixed una vez en el archivo de edmx, a continuación, después cada vez que actualice su modelo, antes de registrar en el código (suponiendo que tiene algo de vida control de versiones de configuración TFS), comparar con la última versión y fusionar los cambios en consecuencia.De esta manera no tienes que actualizar cada línea manualmente. No es la mejor manera, pero es mejor que hacerlo manualmente al menos.

0

Ésta es Mohamed Cassim respuesta, pero se está trabajando para EF6

static Dictionary<string, string> replacements = new Dictionary<string, string>() 
    { 
     { "<Property Name=\"RowVersion\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"RowVersion\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"rowversion\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"rowversion\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"RowVer\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"RowVer\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"rowver\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"rowver\" Type=\"Binary\" Nullable=\"false\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"RowVersion\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"RowVersion\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"rowversion\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"rowversion\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"RowVer\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"RowVer\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 

     { "<Property Name=\"rowver\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" />", 
      "<Property Name=\"rowver\" Type=\"Binary\" MaxLength=\"8\" FixedLength=\"true\" annotation:StoreGeneratedPattern=\"Computed\" ConcurrencyMode=\"Fixed\" />"}, 
    }; 

    static void Main(string[] args) 
    { 
     // find all .edmx 
     string directoryPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 
     foreach (var file in Directory.GetFiles(directoryPath)) 
     { 
      // only edmx 
      if (!file.EndsWith(".edmx")) 
       continue; 

      Console.WriteLine("File Name Found : " + file); 

      // read file 
      var fileContents = File.ReadAllText(file); 

      // replace lines 
      foreach (var item in replacements) 
       fileContents = fileContents.Replace(item.Key, item.Value); 

      // overwite file 
      File.WriteAllText(file, fileContents); 

      Console.WriteLine("\nFile : " + file + "Changed"); 
     } 
    } 
Cuestiones relacionadas