Самое простое решение, которое мы придумали, - это создать новое консольное приложение, которое выполняло низкоуровневую работу по переименованию всего в файле edmx; приложение можно добавить в меню инструментов Visual Studio (добавить внешний инструмент) с помощью «arguments» = $ (ItemPath), «начального каталога» = $ (ItemDir), «подсказки для аргументов» = true и «использовать окно вывода» = true, тогда может выполняться с выбранным файлом EDMX. В нашем случае нам нужно было убрать подчеркивания и преобразовать имена в регистр верблюдов (интерпретируя подчеркивание как разделитель слов), в дополнение к удалению префикса.
Я опущу оставшуюся часть кода (например, метод Transform.Standard, обработку ошибок и удаление дополнительных параметров), потому что он слишком плохо написан для совместного использования и слишком поздно ночью для рефакторинга: P; но достаточно просто интерпретировать остальные аргументы после первого как строки, которые нужно удалить из имен и т. д. - этот основной код касается только изменений, необходимых для файла EDMX. Если вы используете это как внешний инструмент от VS, вы можете указать остальные строки после $ (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, используемого приведенным выше кодом. Кроме того, обратите внимание, что это работает для Entity Framework 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 при вызове инструмента. Или, я полагаю, вы можете просто жестко закодировать их, если вам не нужно многократное использование инструмента:)