我試圖讓表名自動重命名以去掉EF4中的前導前綴。我知道它可以在GUI中完成,但是,我的公司在Visio中創建了數據庫模式,並使用它在SQL中創建數據庫創建腳本。我們經常這樣做,有時會有很多表格,所以使用GUI並不是一個理想的解決方案。導入時的EF4 Strip表前綴
是否需要修改.edmx文件上的屬性以從數據庫表中剝離已定義的前綴,以便實體類是我們期望的方式?
我試圖讓表名自動重命名以去掉EF4中的前導前綴。我知道它可以在GUI中完成,但是,我的公司在Visio中創建了數據庫模式,並使用它在SQL中創建數據庫創建腳本。我們經常這樣做,有時會有很多表格,所以使用GUI並不是一個理想的解決方案。導入時的EF4 Strip表前綴
是否需要修改.edmx文件上的屬性以從數據庫表中剝離已定義的前綴,以便實體類是我們期望的方式?
我們想出的最簡單的解決方案是創建一個新的控制檯應用程序,它執行重命名edmx文件中所有內容的低級別工作;可以通過'arguments'= $(ItemPath),'initial directory'= $(ItemDir),'提示參數'= true'和'使用輸出窗口'將應用程序添加到Visual Studio的工具菜單(添加外部工具) = true,然後可以選擇EDMX文件執行。在我們的例子中,我們需要去除下劃線,並將名稱轉換爲駱駝大小寫(將下劃線解釋爲字詞分隔符),併除去前綴。
我會忽略代碼的其餘部分(如Transform.Standard方法,錯誤處理和附加參數的剝離),因爲它寫得太糟糕了,因此在重構時太晚了:P;但很容易解釋第一個字符串之後的其餘參數,從名稱等等剝離 - 這個主要代碼只是關於EDMX文件所需的修改。如果你使用VS作爲外部工具,你可以在'arguments'中的$(ItemPath)之後指定其餘的字符串。
請注意,這並未廣泛測試,並且其他EDMX文件中可能還有其他信息,但我沒有注意到(但我懷疑它)。另外,我從網上的其他地方獲得了部分代碼,但沒有記下確切的地方,所以很抱歉!信用應該是相應的。此外,當然,這將是作爲一個擴展的VS2010好多了,但是我根本沒有足夠的時間來做到這一點 - 如果你的某個地方鏈接它,我就會改用;)
if (_args.Count < 1) return;
string file = _args.First();
if (!File.Exists(file))
{
wait("Could not find specified file.");
return;
}
if (Path.GetExtension(file) != ".edmx")
{
wait("This works only on EDMX files.");
return;
}
//processing:
Console.WriteLine("Creating backup: " + Path.ChangeExtension(file, ".bak"));
File.Copy(file, Path.ChangeExtension(file, ".bak"), true);
Console.WriteLine("Reading target document...");
XDocument xdoc = XDocument.Load(file);
const string CSDLNamespace = "http://schemas.microsoft.com/ado/2008/09/edm";
const string MSLNamespace = "http://schemas.microsoft.com/ado/2008/09/mapping/cs";
const string DiagramNamespace = "http://schemas.microsoft.com/ado/2008/10/edmx";
XElement csdl = xdoc.Descendants(XName.Get("Schema", CSDLNamespace)).First();
XElement msl = xdoc.Descendants(XName.Get("Mapping", MSLNamespace)).First();
XElement designerDiagram = xdoc.Descendants(XName.Get("Diagram", DiagramNamespace)).First();
//modifications for renaming everything, not just table names:
string[] CSDLpaths = new string[]
{
"EntityContainer/EntitySet.Name",
"EntityContainer/EntitySet.EntityType",
"EntityContainer/AssociationSet/End.EntitySet",
"EntityType.Name",
"EntityType/Key/PropertyRef/Name",
"EntityType/Property.Name",
"EntityType/NavigationProperty.Name",
"Association/End.Type",
"Association//PropertyRef.Name",
};
#region CSDL2
Console.WriteLine("Modifying CSDL...");
Console.WriteLine(" - modifying entity sets...");
foreach (var entitySet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("EntitySet", CSDLNamespace)))
{
entitySet.Attribute("Name").Value = Transform.Standard(entitySet.Attribute("Name").Value);
entitySet.Attribute("EntityType").Value = Transform.Standard(entitySet.Attribute("EntityType").Value);
}
Console.WriteLine(" - modifying association sets...");
foreach (var associationSet in csdl.Element(XName.Get("EntityContainer", CSDLNamespace)).Elements(XName.Get("AssociationSet", CSDLNamespace)))
{
foreach (var end in associationSet.Elements(XName.Get("End", CSDLNamespace)))
{
end.Attribute("EntitySet").Value = Transform.Standard(end.Attribute("EntitySet").Value);
}
}
Console.WriteLine(" - modifying entity types...");
foreach (var entityType in csdl.Elements(XName.Get("EntityType", CSDLNamespace)))
{
entityType.Attribute("Name").Value = Transform.Standard(entityType.Attribute("Name").Value);
foreach (var key in entityType.Elements(XName.Get("Key", CSDLNamespace)))
{
foreach (var propertyRef in key.Elements(XName.Get("PropertyRef", CSDLNamespace)))
{
propertyRef.Attribute("Name").Value = Transform.Standard(propertyRef.Attribute("Name").Value);
}
}
foreach (var property in entityType.Elements(XName.Get("Property", CSDLNamespace)))
{
property.Attribute("Name").Value = Transform.Standard(property.Attribute("Name").Value);
}
foreach (var navigationProperty in entityType.Elements(XName.Get("NavigationProperty", CSDLNamespace)))
{
navigationProperty.Attribute("Name").Value = Transform.Standard(navigationProperty.Attribute("Name").Value);
}
}
Console.WriteLine(" - modifying associations...");
foreach (var association in csdl.Elements(XName.Get("Association", CSDLNamespace)))
{
foreach (var end in association.Elements(XName.Get("End", CSDLNamespace)))
{
end.Attribute("Type").Value = Transform.Standard(end.Attribute("Type").Value);
}
foreach (var propref in association.Descendants(XName.Get("PropertyRef", CSDLNamespace)))
{
//propertyrefs are contained in constraints
propref.Attribute("Name").Value = Transform.Standard(propref.Attribute("Name").Value);
}
}
#endregion
#region MSL2
Console.WriteLine("Modifying MSL...");
Console.WriteLine(" - modifying entity set mappings...");
foreach (var entitySetMapping in msl.Element(XName.Get("EntityContainerMapping", MSLNamespace)).Elements(XName.Get("EntitySetMapping", MSLNamespace)))
{
entitySetMapping.Attribute("Name").Value = Transform.Standard(entitySetMapping.Attribute("Name").Value);
foreach (var entityTypeMapping in entitySetMapping.Elements(XName.Get("EntityTypeMapping", MSLNamespace)))
{
entityTypeMapping.Attribute("TypeName").Value = Transform.Standard(entityTypeMapping.Attribute("TypeName").Value);
foreach
(var scalarProperty in
(entityTypeMapping.Element(XName.Get("MappingFragment", MSLNamespace))).Elements(XName.Get("ScalarProperty", MSLNamespace))
)
{
scalarProperty.Attribute("Name").Value = Transform.Standard(scalarProperty.Attribute("Name").Value);
}
}
}
Console.WriteLine(" - modifying association set mappings...");
foreach (var associationSetMapping in msl.Element(XName.Get("EntityContainerMapping", MSLNamespace)).Elements(XName.Get("AssociationSetMapping", MSLNamespace)))
{
foreach (var endProperty in associationSetMapping.Elements(XName.Get("EndProperty", MSLNamespace)))
{
foreach (var scalarProperty in endProperty.Elements(XName.Get("ScalarProperty", MSLNamespace)))
{
scalarProperty.Attribute("Name").Value = Transform.Standard(scalarProperty.Attribute("Name").Value);
}
}
}
#endregion
#region Designer
Console.WriteLine("Modifying designer content...");
foreach (var item in designerDiagram.Elements(XName.Get("EntityTypeShape", DiagramNamespace)))
{
item.Attribute("EntityType").Value = Transform.Standard(item.Attribute("EntityType").Value);
}
#endregion
Console.WriteLine("Writing result...");
using (XmlTextWriter writer = new XmlTextWriter(args[0], Encoding.Default))
{
writer.Formatting = Formatting.Indented;
xdoc.WriteTo(writer);
}
編輯:添加上面代碼使用的Transform類。此外,請注意,這適用於實體框架4.0 - 更高版本可能有略微不同的EDMX結構(我不確定),因此可能需要修改代碼以解釋這一點。
public class Transform
{
public static string Standard(string initial, IEnumerable<string> eliminations = null)
{
Regex re = new Regex(@"(\w+)(\W*?)$", RegexOptions.Compiled);
Regex camelSplit = new Regex(@"(?<!^)(?=[A-Z])", RegexOptions.Compiled);
return re.Replace(initial, new MatchEvaluator((Match m) =>
{
string name = m.Groups[1].Value;
var parts = name.Split('_').AsEnumerable();
if (parts.Count() == 1 && IsMixedCase(name))
{
string result = string.Concat(camelSplit.Split(name).Except(eliminations, StringComparer.CurrentCultureIgnoreCase));
return result + m.Groups[2];
}
else
{
parts = parts.Select(s => CultureInfo.CurrentCulture.TextInfo.ToTitleCase(s.ToLower()));
parts = parts.Except(eliminations, StringComparer.CurrentCultureIgnoreCase);
return string.Concat(parts) + m.Groups[2];
}
}));
}
public static bool IsMixedCase(string name)
{
int lower = 0, total = 0;
for (int i = 0; i < name.Length; i++)
{
if (char.IsLower(name, i)) lower++;
if (char.IsLetter(name, i)) total++;
}
return lower != 0 && lower != total;
}
}
現在你可以在Main方法寫一點點代碼,可以接受的參數(除了這將是文件名的第一個),並以後將它們傳遞到eliminations
參數;這些可能是需要從名稱中刪除的字符串,在我的情況下是前綴。然後,您可以在調用該工具時從Visual Studio工具界面中指定這些字符串。或者我想你可以硬編碼他們,如果你不關心重複使用該工具:)
我不知道任何內置剝離表前綴的功能,但可以打開.edmx文件爲XML(使用VS中的Open With)並使用簡單替換來替換前綴。
這對我來說非常合適,謝謝! – Barn 2011-07-04 14:06:35
對於驗收中的長時間延遲感到抱歉!我的一位同事發現了一個工作解決方案,由於我不再在該公司工作,我完全忘記了他發現的東西。但是你的回答很好,很有效。所以就像你說的那樣:給它信用卡! – 2011-11-21 19:03:27
@Alex我面臨同樣的問題。我只需要在你的解決方案中做一些澄清...我已經創建了一個控制檯應用程序..我應該在哪裏添加上述代碼?那麼如何執行它...這是完全新的...請幫助我 – Xavier 2013-02-25 06:25:13