Как автоматизировать установку ConcurrencyMode = Исправлено во всех столбцах RowVersion?
EF по умолчанию не имеет управления concurrency (последние победы записи), что позволяет потерять обновления.
Выполнение оптимистичных проверок concurrency можно явно настроить, установив ConcurrencyMode = Исправлено в столбце RowVersion.
Как мы можем автоматизировать установку ConcurrencyMode = Исправлено в столбцах RowVersion во всех таблицах?
Чтобы сделать это вручную при воссоздании EF-модели из базы данных, мы рискуем забыть ее без управления concurrency.
Ответы
Ответ 1
Это похоже на ответ Мохамеда Кассима, но я обновил код для использования поиска атрибутов XML и заменил вместо замены строки, поскольку дизайнер может изменить порядок атрибутов, или другие свойства могут иметь разные значения.
Сохраните это как FixVersionColumnConcurrencyMode.cs
, запустите csc FixVersionColumnConcurrencyMode.cs
и запустите полученный файл FixVersionColumnConcurrencyMode.exe в той же папке, что и файл .edmx. Вы также можете выполнить выполнение пост-сборки проекта.
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);
}
}
}
}
Ответ 2
В EF6 конструктор установит ConcurrencyMode = Исправлено в столбцах rowversion при создании модели из базы данных. Посмотрите Дизайнер: Автоматическая настройка ConcurrencyMode = Исправлено в столбцах rowversion. До тех пор нам придется делать это вручную.
Ответ 3
Похоже, эта функция не будет использоваться для EF 5 или EF 6.
Я взломал быстрое консольное приложение, чтобы обновить edmx после генерации базы данных сначала.
Просто отпустите файл в том же каталоге вашего файла edmx и запустите после каждой регенерации.
Будет работать для любого из следующих столбцов:
RowVersion timestamp NOT NULL
rowversion timestamp NOT NULL
RowVer timestamp NOT NULL
rowver timestamp NOT NULL
Здесь вы можете получить консольное приложение https://dl.dropbox.com/u/3576345/EFConcurrencyFixed.exe
или используйте этот фрагмент кода в своем консольном приложении.
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);
}
}
}
Ответ 4
Я не делал этого сам (но, скорее всего, скоро это нужно), но должно быть возможно изменить инструмент, используемый для генерации кода из .edmx.
Здесь - статья, объясняющая это для VS2008. Я думаю, что этот процесс будет примерно таким же для VS2010 и VS2012.
В настоящее время я не уверен, сможет ли это сделать галочку с помощью ConcurrencyMode.
Ответ 5
Когда вы добавили ConcurrencyMode=Fixed
один раз в свой файл edmx, а затем каждый раз, когда вы обновляете свою модель, перед регистрацией кода (при условии, что у вас есть версия TFS для управления версиями), сравните с последней версией и смените изменения соответственно, Таким образом, вам не нужно обновлять каждую строку вручную. Не лучший способ, но лучше, чем делать это вручную по крайней мере.
Ответ 6
Мне стало скучно с установкой ConcurrencyMode вручную, поэтому я написал небольшую утилиту для ее автоматизации. Вы можете использовать его для установки режима для определенных типов (timestamp/rowversion) или для имен столбцов, соответствующих определенным шаблонам регулярных выражений.
http://blog.wezeku.com/2014/04/28/fixefconcurrencymodes/
https://github.com/wezeku/FixEFConcurrencyModes
Ответ 7
Это ответ Мохамеда Кассима, но он работает для 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");
}
}