EF默认为无并发控制(最后写入获胜),允许丢失更新。 通过在RowVersion列上设置ConcurrencyMode = Fixed,可以显式配置执行乐观并发检查。
如何在所有表中的RowVersion列上自动设置ConcurrencyMode = Fixed? 在从数据库重新创建EF模型时必须手动执行此操作,我们可能会忘记它在没有并发控制的情况下运行。
答案 0 :(得分:6)
这与Mohamed Cassim的回答类似,但我更新了代码以使用XML属性搜索和替换,而不是字符串替换,因为设计者可以更改属性的顺序,或者其他属性可以具有不同的值
将其另存为FixVersionColumnConcurrencyMode.cs
,运行csc FixVersionColumnConcurrencyMode.cs
,然后在.edmx文件所在的文件夹中运行生成的FixVersionColumnConcurrencyMode.exe。您还可以使其执行项目的后期构建。
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);
}
}
}
}
答案 1 :(得分:4)
在EF6中,设计人员在从数据库创建模型时将在rowversion列上设置ConcurrencyMode = Fixed。参见Designer: Automate setting ConcurrencyMode=Fixed on rowversion columns。在此之前,我们必须手动完成此操作。
答案 2 :(得分:4)
似乎这样的功能不会出现在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);
}
}
}
答案 3 :(得分:1)
我自己没有这样做(但很快就可能需要),但应该可以更改用于从.edmx生成代码的工具。
Here是一篇为VS2008解释的文章。我想VS2010和VS2012的过程大致相同。
但是,我现在还不确定这是否能够以任何方式解决ConcurrencyMode问题。答案 4 :(得分:1)
当您在edmx文件中添加ConcurrencyMode=Fixed
一次,然后每次更新模型时,在签入代码之前(假设您有一些版本控制生命TFS设置),请与最新版本进行比较并合并相应地改变。这样您就不必手动更新每一行。不是最好的方式,但比手动至少更好。
答案 5 :(得分:0)
我厌倦了手动设置ConcurrencyMode,所以我写了一个小实用程序来自动化它。您可以使用它来设置某些类型的模式(timestamp / rowversion)或匹配某些正则表达式模式的列名。
答案 6 :(得分:0)
这是Mohamed Cassim的答案,但它正在为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");
}
}