我怎样才能从C#类生成数据库表?
有没有人知道一种方法来自动生成给定类的数据库表? 我不是在寻找一个完整的持久层 – 我已经有了一个我正在使用的数据访问解决scheme,但是我突然间必须存储大量类的大量信息,而且我不想创build所有这些表手工。 例如,给以下class级:
class Foo { private string property1; public string Property1 { get { return property1; } set { property1 = value; } } private int property2; public int Property2 { get { return property2; } set { property2 = value; } } }
我期望以下SQL:
CREATE TABLE Foo ( Property1 VARCHAR(500), Property2 INT )
我也想知道如何处理复杂的types。 例如,在前面引用的类中,如果我们将其改为:
class Foo { private string property1; public string Property1 { get { return property1; } set { property1 = value; } } private System.Management.ManagementObject property2; public System.Management.ManagementObject Property2 { get { return property2; } set { property2 = value; } } }
我怎么处理这个?
我已经着眼于试图通过reflection来自动生成数据库脚本来枚举每个类的属性,但它很笨重,而且复杂的数据types让我难以忍受。
这真的很晚,我只花了10分钟左右的时间,所以它非常草率,但它确实有效,并且会给你一个很好的起点:
using System; using System.Collections.Generic; using System.Text; using System.Reflection; namespace TableGenerator { class Program { static void Main(string[] args) { List<TableClass> tables = new List<TableClass>(); // Pass assembly name via argument Assembly a = Assembly.LoadFile(args[0]); Type[] types = a.GetTypes(); // Get Types in the assembly. foreach (Type t in types) { TableClass tc = new TableClass(t); tables.Add(tc); } // Create SQL for each table foreach (TableClass table in tables) { Console.WriteLine(table.CreateTableScript()); Console.WriteLine(); } // Total Hacked way to find FK relationships! Too lazy to fix right now foreach (TableClass table in tables) { foreach (KeyValuePair<String, Type> field in table.Fields) { foreach (TableClass t2 in tables) { if (field.Value.Name == t2.ClassName) { // We have a FK Relationship! Console.WriteLine("GO"); Console.WriteLine("ALTER TABLE " + table.ClassName + " WITH NOCHECK"); Console.WriteLine("ADD CONSTRAINT FK_" + field.Key + " FOREIGN KEY (" + field.Key + ") REFERENCES " + t2.ClassName + "(ID)"); Console.WriteLine("GO"); } } } } } } public class TableClass { private List<KeyValuePair<String, Type>> _fieldInfo = new List<KeyValuePair<String, Type>>(); private string _className = String.Empty; private Dictionary<Type, String> dataMapper { get { // Add the rest of your CLR Types to SQL Types mapping here Dictionary<Type, String> dataMapper = new Dictionary<Type, string>(); dataMapper.Add(typeof(int), "BIGINT"); dataMapper.Add(typeof(string), "NVARCHAR(500)"); dataMapper.Add(typeof(bool), "BIT"); dataMapper.Add(typeof(DateTime), "DATETIME"); dataMapper.Add(typeof(float), "FLOAT"); dataMapper.Add(typeof(decimal), "DECIMAL(18,0)"); dataMapper.Add(typeof(Guid), "UNIQUEIDENTIFIER"); return dataMapper; } } public List<KeyValuePair<String, Type>> Fields { get { return this._fieldInfo; } set { this._fieldInfo = value; } } public string ClassName { get { return this._className; } set { this._className = value; } } public TableClass(Type t) { this._className = t.Name; foreach (PropertyInfo p in t.GetProperties()) { KeyValuePair<String, Type> field = new KeyValuePair<String, Type>(p.Name, p.PropertyType); this.Fields.Add(field); } } public string CreateTableScript() { System.Text.StringBuilder script = new StringBuilder(); script.AppendLine("CREATE TABLE " + this.ClassName); script.AppendLine("("); script.AppendLine("\t ID BIGINT,"); for (int i = 0; i < this.Fields.Count; i++) { KeyValuePair<String, Type> field = this.Fields[i]; if (dataMapper.ContainsKey(field.Value)) { script.Append("\t " + field.Key + " " + dataMapper[field.Value]); } else { // Complex Type? script.Append("\t " + field.Key + " BIGINT"); } if (i != this.Fields.Count - 1) { script.Append(","); } script.Append(Environment.NewLine); } script.AppendLine(")"); return script.ToString(); } } }
我把这些类放在一个程序集中来testing它:
public class FakeDataClass { public int AnInt { get; set; } public string AString { get; set; } public float AFloat { get; set; } public FKClass AFKReference { get; set; } } public class FKClass { public int AFKInt { get; set; } }
它生成了以下SQL:
CREATE TABLE FakeDataClass ( ID BIGINT, AnInt BIGINT, AString NVARCHAR(255), AFloat FLOAT, AFKReference BIGINT ) CREATE TABLE FKClass ( ID BIGINT, AFKInt BIGINT ) GO ALTER TABLE FakeDataClass WITH NOCHECK ADD CONSTRAINT FK_AFKReference FOREIGN KEY (AFKReference) REFERENCES FKClass(ID) GO
一些进一步的想法…我会考虑添加一个属性,如[SqlTable]到你的类,这样它只会为你想要的类生成表。 此外,这可以清理了一吨,固定的错误,优化(FK检查器是一个笑话)等等等等等等等等等等等。
@Jonathan Holland
哇,我认为这是我见过的最原始的工作放在一个StackOverflow后。 做得好。 但是 ,不应将DDL语句构build为string,而应该使用SQL 2005引入的SQL Serverpipe理对象类。
David Hayden 在SQL Server 2005中使用C#和SQL Serverpipe理对象(SMO)创build了一个表格- 代码生成 ,演示了如何使用SMO创build表格。 强types的对象使得像下面这样的方法变得轻而易举:
// Create new table, called TestTable Table newTable = new Table(db, "TestTable");
和
// Create a PK Index for the table Index index = new Index(newTable, "PK_TestTable"); index.IndexKeyType = IndexKeyType.DriPrimaryKey;
VanOrman,如果你使用的是SQL 2005,那么SMO肯定是你解决scheme的一部分。
我认为对于复杂的数据types,您应该通过指定一个ToDB()方法来扩展它们,该方法持有自己的实现来在DB中创build表,并且这样它就成为自动recursion。
在http://createschema.codeplex.com/试试我的CreateSchema扩展方法;
它为包含CREATE TABLE脚本的任何对象返回一个string。
截至2016年(我认为),您可以使用Entity Framework 6 Code First从poco c#类生成SQL模式或使用Database First从sql生成c#代码。 代码优先到DB演练
对于复杂的types,您可以recursion地将您遇到的每一个转换为它自己的表,然后尝试pipe理外键关系。
您可能还需要预先指定哪些类将转换为表格。 对于您希望在数据库中反映的复杂数据而不会使模式膨胀,可以为其他types提供一个或多个表。 这个例子使用多达4:
CREATE TABLE MiscTypes /* may have to include standard types as well */ ( TypeID INT, TypeName VARCHAR(...) ) CREATE TABLE MiscProperties ( PropertyID INT, DeclaringTypeID INT, /* FK to MiscTypes */ PropertyName VARCHAR(...), ValueTypeID INT /* FK to MiscTypes */ ) CREATE TABLE MiscData ( ObjectID INT, TypeID INT ) CREATE TABLE MiscValues ( ObjectID INT, /* FK to MiscData*/ PropertyID INT, Value VARCHAR(...) )
你可以在这里做相反的,数据库表到C#类: http : //pureobjects.com/dbCode.aspx
另外…也许你可以使用一些工具,如Visio(不知道如果Visio这样做,但我认为它),逆向工程你的类到UML,然后使用UML来生成DB架构…或者可能使用像这样的工具http://www.tangiblearchitect.net/visual-studio/
我知道你正在寻找一个完整的持久层,但NHibernate的hbm2ddl任务几乎可以做到这一点。
有一个NAnt任务可以调用它,这可能是有趣的。
@PortMan,
SQL DataObjects很酷,我不知道它们。 这将明确地采取我的代码中的一些咕噜作品。
实际上,我原来的代码很整齐,分布在三个类中,但是在它工作之后,我决定把它合并成一个单一的粘贴。
我会考虑添加[SqlTable]属性到域类,以及[主键]到主ID键,而不是让代码自动生成一个ID。
通过这样做,代码将能够正确地将PK's,Index和FK约束放置在正确的列上。
然而,VanOrMan可能会使用我的代码来生成99%的需求,然后在运行之前在编辑器中调整SQL。
亚音速也是另一种select。 我经常用它来生成映射到数据库的实体类。 它有一个命令行工具,可以让你指定表,types和其他有用的东西
尝试使用DaiteMappingTool for .net。 它可以帮助您生成类。 下载表格在这里
有一个免费的应用程序,Schematrix从DB生成类,检查是否也是相反的:) http://www.schematrix.com/products/schemacoder/download.aspx