我正在尝试自动重命名表名以去除EF4中的前导前缀。我知道它可以在GUI中完成,但是,我的公司在Visio中创建了数据库模式,并使用它在SQL中创建数据库创建脚本。我们经常这样做,有时会有很多表,所以使用GUI并不是一个理想的解决方案。
有没有办法修改.edmx文件的属性以从DB表中去除已定义的前缀,以便实体类是我们想要的呢?
答案 0 :(得分:7)
我们提出的最简单的解决方案是创建一个新的控制台应用程序,它完成了重命名edmx文件中所有内容的低级工作;应用程序可以添加到Visual Studio的工具菜单(添加外部工具),其中'arguments'= $(ItemPath),'initial directory'= $(ItemDir),'prompt for arguments'= true和'use output window' = 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类。此外,请注意,这适用于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工具界面指定这些字符串。或者我想如果你不太关心重复使用该工具,你可以对它们进行硬编码:)
答案 1 :(得分:0)
我不知道有关剥离表前缀的任何内置功能,但您可以将.edmx文件作为XML打开(在VS中使用Open With)并使用简单替换来替换前缀。