我正在使用的数据库具有表名,例如“table_name”。这没关系,但我想以“TableName”格式生成类,以C#,Pascal风格工作。
这可能吗?
答案 0 :(得分:3)
更新:要与EF6一起使用,请参阅此页面上的其他答案。
感谢Alex's answer,我现在已将此代码扩展为解决此问题的完整解决方案。因为它占用了我一天的大部分时间,所以我发布这里是为了帮助其他人面对同样的挑战。这包括一个完整的类来操作edmx文件(这里没有漂亮的代码点),它在不同的输入字符串上传递相当详细的单元测试:
一些例子:
some_class> SomeClass的
_some_class_> SomeClass的
some_1_said> Some1Said
我还有一些其他问题要处理:
首先可选择不更换下划线,同时仍然将字符串更改为pascal情况(由于列名称如“test_string”和“teststring”,否则两者都解析为“TestString”,导致冲突)。
其次,我的代码在这里采用一个输入参数来修改生成的对象上下文类名。
最后,我最初并不确定如何在修改edmx后更新设计器文件,所以我已经包含了确切的步骤。我建议在Visual Studio中创建一个预构建步骤,这样可以节省从修改后的数据库模式更新的一些剩余工作。
更新EDMX文件以反映数据库更改
双击edmx文件以显示设计图面。
右键单击设计图面并选择“从数据库更新模型”。
选择“是包含连接字符串中的敏感信息”。
取消选中“在App Config中保存实体连接设置”(我们已经有了这些设置)。
选择适当的数据库。在添加屏幕中,选择表格,视图等。
保留复数和外键选项。如果从fresh创建edmx文件,那么 可以选择输入型号名称。您可以更改或保留此内容。
点击完成。
在edmx文件上运行以下代码。
根据应用程序的状态,您可能会在此处看到错误,直到下一步。
右键单击要更新的edmx文件,然后在Visual Studio中选择“运行自定义工具”。这将是一个问题 要更新的designer.cs(C#)文件。
运行build以检查没有编译器错误。
运行测试以确保应用程序正常运行。
根据申请,应该预期此后的任何应用程序问题 已经做出的改变。
完整替换edmx文件。
删除edmx文件,随身携带设计器文件。
右键单击实体文件夹
从创建文件对话框中,选择ADO.NET实体数据模型。将其命名为您希望对象上下文的类名称(重要)。 此值在连接字符串中引用,因此如果出现问题,请查看您的应用配置。
在选择模型内容时,请从数据库中选择生成。
按照步骤3的上述说明进行操作。
using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace EdmxStringFormatter
{
public class Program
{
static void Main(string[] args)
{
if (args.Length < 1) return;
string filePath = args[0];
string entityName = null;
// Optionally do not replace underscores which
// helps with naming collisions with siimilarly named
// columns on some database tables.
bool replaceUnderscores = true;
// Allow for the replacement of the object context class name, which is useful
// where multiple databases have edmx files.
bool doEntityNameReplace = false;
if (args.Length > 1)
{
entityName = args[1];
doEntityNameReplace = true;
}
if (args.Length > 2)
{
replaceUnderscores = args[2] != "0";
}
if (!File.Exists(filePath))
{
StopWithMessage("Could not find specified file.");
return;
}
if (Path.GetExtension(filePath) != ".edmx")
{
StopWithMessage("This works only on EDMX files.");
return;
}
// Processing:
Console.WriteLine("Creating backup: " + Path.ChangeExtension(filePath, ".bak"));
File.Copy(filePath, Path.ChangeExtension(filePath, ".bak"), true);
Console.WriteLine("Reading target document...");
XDocument xdoc = XDocument.Load(filePath);
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";
const string CSNameSpace = "http://schemas.microsoft.com/ado/2008/09/mapping/cs";
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:
#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 = FormatString(entitySet.Attribute("Name").Value, replaceUnderscores);
entitySet.Attribute("EntityType").Value = FormatString(entitySet.Attribute("EntityType").Value, replaceUnderscores);
}
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 = FormatString(end.Attribute("EntitySet").Value, replaceUnderscores);
}
}
Console.WriteLine(" - modifying entity types...");
foreach (var entityType in csdl.Elements(XName.Get("EntityType", CSDLNamespace)))
{
entityType.Attribute("Name").Value = FormatString(entityType.Attribute("Name").Value, replaceUnderscores);
foreach (var key in entityType.Elements(XName.Get("Key", CSDLNamespace)))
{
foreach (var propertyRef in key.Elements(XName.Get("PropertyRef", CSDLNamespace)))
{
propertyRef.Attribute("Name").Value = FormatString(propertyRef.Attribute("Name").Value, replaceUnderscores);
}
}
foreach (var property in entityType.Elements(XName.Get("Property", CSDLNamespace)))
{
property.Attribute("Name").Value = FormatString(property.Attribute("Name").Value, replaceUnderscores);
}
foreach (var navigationProperty in entityType.Elements(XName.Get("NavigationProperty", CSDLNamespace)))
{
navigationProperty.Attribute("Name").Value = FormatString(navigationProperty.Attribute("Name").Value, replaceUnderscores);
}
}
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 = FormatString(end.Attribute("Type").Value, replaceUnderscores);
}
foreach (var propref in association.Descendants(XName.Get("PropertyRef", CSDLNamespace)))
{
//propertyrefs are contained in constraints
propref.Attribute("Name").Value = FormatString(propref.Attribute("Name").Value, replaceUnderscores);
}
}
#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 = FormatString(entitySetMapping.Attribute("Name").Value, replaceUnderscores);
foreach (var entityTypeMapping in entitySetMapping.Elements(XName.Get("EntityTypeMapping", MSLNamespace)))
{
entityTypeMapping.Attribute("TypeName").Value = FormatString(entityTypeMapping.Attribute("TypeName").Value, replaceUnderscores);
foreach
(var scalarProperty in
(entityTypeMapping.Element(XName.Get("MappingFragment", MSLNamespace))).Elements(XName.Get("ScalarProperty", MSLNamespace))
)
{
scalarProperty.Attribute("Name").Value = FormatString(scalarProperty.Attribute("Name").Value, replaceUnderscores);
}
}
}
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 = FormatString(scalarProperty.Attribute("Name").Value, replaceUnderscores);
}
}
}
#endregion
#region Designer
Console.WriteLine("Modifying designer content...");
foreach (var item in designerDiagram.Elements(XName.Get("EntityTypeShape", DiagramNamespace)))
{
item.Attribute("EntityType").Value = FormatString(item.Attribute("EntityType").Value, replaceUnderscores);
}
#endregion
// Optionally replace the entity name in case the default of "Entity" is not
// sufficient for your needs.
if (doEntityNameReplace)
{
Console.WriteLine("Modifying entity name refs...");
// CSDL
xdoc.Descendants(XName.Get("EntityContainer", CSDLNamespace)).First().Attribute("Name").Value = entityName;
// Diagram
xdoc.Descendants(XName.Get("Diagram", DiagramNamespace)).First().Attribute("Name").Value = entityName;
// Diagram
xdoc.Descendants(XName.Get("EntityContainerMapping", CSNameSpace)).First().Attribute("CdmEntityContainer").Value = entityName;
}
Console.WriteLine("Writing result...");
using (XmlTextWriter writer = new XmlTextWriter(filePath, Encoding.Default))
{
writer.Formatting = Formatting.Indented;
xdoc.WriteTo(writer);
}
}
/// <summary>
/// Formats the string to pascal case, additionally checking for a period
/// in the string (in which case it skips past the period, which indicates
/// the use of namespace in a string.
/// </summary>
/// <param name="str"></param>
/// <param name="replaceUnderscores"></param>
/// <returns></returns>
private static string FormatString(string str, bool replaceUnderscores = true)
{
char[] chars = str.ToCharArray();
var sb = new StringBuilder();
bool previousCharWasUpper = false;
bool lastOperationWasToLower = false;
int startPos = 0;
if (str.Contains("."))
{
if (str.IndexOf(".") < (str.Length - 1))
{
startPos = str.IndexOf(".") + 1;
}
sb.Append(str.Substring(0, startPos));
}
for (int i = startPos; i < chars.Length; i++)
{
char character = chars[i];
if (Char.IsLetter(character))
{
if (Char.IsLower(character))
{
bool toUpper = false;
if (i > 0)
{
// Look at the previous char to see if not a letter
if (!Char.IsLetter(chars[i - 1]))
{
toUpper = true;
}
}
if (i == 0 || toUpper)
{
character = Char.ToUpper(character);
lastOperationWasToLower = false;
}
}
else // IsUpper = true
{
if (previousCharWasUpper || lastOperationWasToLower)
{
character = Char.ToLower(character);
lastOperationWasToLower = true;
}
}
previousCharWasUpper = Char.IsUpper(character);
sb.Append(character);
}
else
{
if (Char.IsDigit(character))
{
sb.Append(character);
previousCharWasUpper = false;
lastOperationWasToLower = false;
}
else if(!replaceUnderscores)
{
if(character == '_')
{
sb.Append(character);
}
}
}
}
return sb.ToString();
}
private static void StopWithMessage(string str)
{
Console.WriteLine(str);
Console.ReadLine();
throw new InvalidOperationException("Cannot continue.");
}
}
}
适应Visual Studio 2013&amp; EF6
代码命名空间需要稍微调整才能使其与 EF6一起使用
const string CSDLNamespace = "http://schemas.microsoft.com/ado/2009/11/edm";
const string MSLNamespace = "http://schemas.microsoft.com/ado/2009/11/mapping/cs";
const string DiagramNamespace = "http://schemas.microsoft.com/ado/2009/11/edmx";
const string CSNameSpace = "http://schemas.microsoft.com/ado/2009/11/mapping/cs";
另外你需要照顾designerDiagram(在我的情况下,它没有找到,所以只用FirstOrDefault()替换了First()并添加了简单的null检查)。
答案 1 :(得分:1)
这是用于Entity Framework 6上下文的完整C#.edmx修改代码(原始答案适用于EF4)。
(由于每个答案的字符数限制而不是编辑的附加答案)
谢谢Chris的意见。我最近重新审视了这个,因为使用此工具的项目已升级到EF6。与EF6一起使用的完整代码复制如下。
请注意,此程序代码现在可以在两个文件上运行 - .edmx和.edmx.diagram文件。 Visual Studio 2013将图表拆分为单独的文件,这需要编辑,否则表/实体表示将不会显示在.edmx设计器表面上。设计器文件的文件路径被接受为第二个参数。
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace EdmxStringFormatter
{
public class Program
{
static void Main(string[] args)
{
if (args.Length < 1) return;
string filePath = args[0];
string designerFilePath = null;
string entityName = null;
// Optionally do not replace underscores which
// helps with naming collisions with siimilarly named
// columns on some database tables.
bool replaceUnderscores = true;
// Allow for the replacement of the object context class name, which is useful
// where multiple databases have edmx files.
bool doEntityNameReplace = false;
if (args.Length > 1)
{
designerFilePath = args[1];
}
if (args.Length > 2)
{
entityName = args[2];
doEntityNameReplace = true;
}
if (args.Length > 3)
{
replaceUnderscores = args[3] != "0";
}
if (!File.Exists(filePath))
{
StopWithMessage("Could not find specified file.");
return;
}
if (Path.GetExtension(filePath) != ".edmx")
{
StopWithMessage("This works only on EDMX files.");
return;
}
TransformEdmx(filePath, replaceUnderscores, doEntityNameReplace, entityName);
TransformEdmxDiagram(designerFilePath, replaceUnderscores);
}
private static void TransformEdmx(string filePath, bool replaceUnderscores, bool doEntityNameReplace, string entityName)
{
// Processing:
Console.WriteLine("Creating backup: " + Path.ChangeExtension(filePath, ".bak"));
File.Copy(filePath, Path.ChangeExtension(filePath, ".bak"), true);
Console.WriteLine("Reading target document...");
XDocument xdoc = XDocument.Load(filePath);
//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";
//const string CSNameSpace = "http://schemas.microsoft.com/ado/2008/09/mapping/cs";
const string CSDLNamespace = "http://schemas.microsoft.com/ado/2009/11/edm";
const string MSLNamespace = "http://schemas.microsoft.com/ado/2009/11/mapping/cs";
const string DiagramNamespace = "http://schemas.microsoft.com/ado/2009/11/edmx";
const string CSNameSpace = "http://schemas.microsoft.com/ado/2009/11/mapping/cs";
XElement csdl = xdoc.Descendants(XName.Get("Schema", CSDLNamespace)).First();
XElement msl = xdoc.Descendants(XName.Get("Mapping", MSLNamespace)).First();
//modifications for renaming everything, not just table names:
#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 = FormatString(entitySet.Attribute("Name").Value, replaceUnderscores);
entitySet.Attribute("EntityType").Value = FormatString(entitySet.Attribute("EntityType").Value,
replaceUnderscores);
}
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 = FormatString(end.Attribute("EntitySet").Value, replaceUnderscores);
}
}
Console.WriteLine(" - modifying entity types...");
foreach (var entityType in csdl.Elements(XName.Get("EntityType", CSDLNamespace)))
{
entityType.Attribute("Name").Value = FormatString(entityType.Attribute("Name").Value, replaceUnderscores);
foreach (var key in entityType.Elements(XName.Get("Key", CSDLNamespace)))
{
foreach (var propertyRef in key.Elements(XName.Get("PropertyRef", CSDLNamespace)))
{
propertyRef.Attribute("Name").Value = FormatString(propertyRef.Attribute("Name").Value,
replaceUnderscores);
}
}
foreach (var property in entityType.Elements(XName.Get("Property", CSDLNamespace)))
{
property.Attribute("Name").Value = FormatString(property.Attribute("Name").Value, replaceUnderscores);
}
foreach (var navigationProperty in entityType.Elements(XName.Get("NavigationProperty", CSDLNamespace)))
{
navigationProperty.Attribute("Name").Value = FormatString(navigationProperty.Attribute("Name").Value,
replaceUnderscores);
}
}
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 = FormatString(end.Attribute("Type").Value, replaceUnderscores);
}
foreach (var propref in association.Descendants(XName.Get("PropertyRef", CSDLNamespace)))
{
//propertyrefs are contained in constraints
propref.Attribute("Name").Value = FormatString(propref.Attribute("Name").Value, replaceUnderscores);
}
}
#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 = FormatString(entitySetMapping.Attribute("Name").Value,
replaceUnderscores);
foreach (var entityTypeMapping in entitySetMapping.Elements(XName.Get("EntityTypeMapping", MSLNamespace)))
{
entityTypeMapping.Attribute("TypeName").Value = FormatString(entityTypeMapping.Attribute("TypeName").Value,
replaceUnderscores);
foreach
(var scalarProperty in
(entityTypeMapping.Element(XName.Get("MappingFragment", MSLNamespace))).Elements(
XName.Get("ScalarProperty", MSLNamespace))
)
{
scalarProperty.Attribute("Name").Value = FormatString(scalarProperty.Attribute("Name").Value,
replaceUnderscores);
}
}
}
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 = FormatString(scalarProperty.Attribute("Name").Value,
replaceUnderscores);
}
}
}
#endregion
// Optionally replace the entity name in case the default of "Entity" is not
// sufficient for your needs.
if (doEntityNameReplace)
{
Console.WriteLine("Modifying entity name refs...");
// CSDL
xdoc.Descendants(XName.Get("EntityContainer", CSDLNamespace)).First().Attribute("Name").Value = entityName;
// Diagram
var diagramDescendants = xdoc.Descendants(XName.Get("Diagram", DiagramNamespace)).FirstOrDefault();
if (diagramDescendants != null)
{
diagramDescendants.Attribute("Name").Value = entityName;
}
// Diagram
xdoc.Descendants(XName.Get("EntityContainerMapping", CSNameSpace)).First().Attribute("CdmEntityContainer").Value
= entityName;
}
Console.WriteLine("Writing result...");
using (XmlTextWriter writer = new XmlTextWriter(filePath, Encoding.Default))
{
writer.Formatting = Formatting.Indented;
xdoc.WriteTo(writer);
}
}
private static void TransformEdmxDiagram(string filePath, bool replaceUnderscores)
{
// Processing:
Console.WriteLine("Creating backup: " + Path.ChangeExtension(filePath, ".bak"));
File.Copy(filePath, Path.ChangeExtension(filePath, ".bak"), true);
Console.WriteLine("Reading target document...");
XDocument xdoc = XDocument.Load(filePath);
const string DiagramNamespace = "http://schemas.microsoft.com/ado/2009/11/edmx";
XElement designerDiagram = xdoc.Descendants(XName.Get("Diagram", DiagramNamespace)).FirstOrDefault();
#region Designer
Console.WriteLine("Modifying designer content...");
if (designerDiagram != null)
{
foreach (var item in designerDiagram.Elements(XName.Get("EntityTypeShape", DiagramNamespace)))
{
item.Attribute("EntityType").Value = FormatString(item.Attribute("EntityType").Value, replaceUnderscores);
}
}
#endregion
Console.WriteLine("Writing result...");
using (XmlTextWriter writer = new XmlTextWriter(filePath, Encoding.Default))
{
writer.Formatting = Formatting.Indented;
xdoc.WriteTo(writer);
}
}
/// <summary>
/// Formats the string to pascal case, additionally checking for a period
/// in the string (in which case it skips past the period, which indicates
/// the use of namespace in a string.
/// </summary>
/// <param name="str"></param>
/// <param name="replaceUnderscores"></param>
/// <returns></returns>
private static string FormatString(string str, bool replaceUnderscores = true)
{
char[] chars = str.ToCharArray();
var sb = new StringBuilder();
bool previousCharWasUpper = false;
bool lastOperationWasToLower = false;
int startPos = 0;
if (str.Contains("."))
{
if (str.IndexOf(".") < (str.Length - 1))
{
startPos = str.IndexOf(".") + 1;
}
sb.Append(str.Substring(0, startPos));
}
for (int i = startPos; i < chars.Length; i++)
{
char character = chars[i];
if (Char.IsLetter(character))
{
if (Char.IsLower(character))
{
bool toUpper = false;
if (i > 0)
{
// Look at the previous char to see if not a letter
if (!Char.IsLetter(chars[i - 1]))
{
toUpper = true;
}
}
if (i == 0 || toUpper)
{
character = Char.ToUpper(character);
lastOperationWasToLower = false;
}
}
else // IsUpper = true
{
if (previousCharWasUpper || lastOperationWasToLower)
{
character = Char.ToLower(character);
lastOperationWasToLower = true;
}
}
previousCharWasUpper = Char.IsUpper(character);
sb.Append(character);
}
else
{
if (Char.IsDigit(character))
{
sb.Append(character);
previousCharWasUpper = false;
lastOperationWasToLower = false;
}
else if (!replaceUnderscores)
{
if (character == '_')
{
sb.Append(character);
}
}
}
}
return sb.ToString();
}
private static void StopWithMessage(string str)
{
Console.WriteLine(str);
Console.ReadLine();
throw new InvalidOperationException("Cannot continue.");
}
}
}
答案 2 :(得分:0)
some_class&gt; SomeClass的
对我不起作用,相反,我得到了:
some_class&gt; SomeClass的
要解决这个问题,我感动了
previousCharWasUpper = false;
几行。它接近旧代码块的末尾。
else
{
if (Char.IsDigit(character))
{
sb.Append(character);
previousCharWasUpper = false;
lastOperationWasToLower = false;
}
else if(!replaceUnderscores)
{
if(character == '_')
{
sb.Append(character);
}
}
}
更改为:
else
{
previousCharWasUpper = false;
if (Char.IsDigit(character))
{
sb.Append(character);
lastOperationWasToLower = false;
}
else if(!replaceUnderscores)
{
if(character == '_')
{
sb.Append(character);
}
}
}