![](/img/trans.png)
[英]How can I generate database tables from C# in order to version control the database?
[英]How can I generate database tables from C# classes?
有沒有人知道為給定類自動生成數據庫表的方法? 我不是在尋找一個完整的持久層 - 我已經有了一個我正在使用的數據訪問解決方案,但我突然要從大量的類中存儲大量信息而且我真的不想創建所有這些表都是手工制作。 例如,給定以下類:
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
)
我也想知道你如何處理復雜的類型。 例如,在之前引用的類中,如果我們將其更改為:
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; }
}
}
我怎么能處理這個?
我已經看過嘗試自己使用反射來自動生成數據庫腳本來枚舉每個類的屬性,但它很笨重,復雜的數據類型讓我感到難過。
這真的很晚了,我只花了大約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();
}
}
}
我把這些類放在一個程序集中來測試它:
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 Checker是一個笑話)等等...只是為了讓你開始。
@Jonathan Holland
哇,我認為這是我見過的最原始的工作,放入StackOverflow帖子。 做得好。 但是 ,您應該使用SQL 2005引入的SQL Server管理對象類,而不是將DDL語句構造為字符串。
David Hayden 在SQL Server 2005中使用C#和SQL Server管理對象(SMO)創建了一個名為“ 創建表”的帖子- 代碼生成 ,介紹了如何使用SMO創建表。 強類型對象使用以下方法輕而易舉:
// 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;
如果您使用的是SQL 2005,VanOrman肯定會讓SMO成為您解決方案的一部分。
在http://createschema.codeplex.com/上試用我的CreateSchema擴展方法。
它返回包含CREATE TABLE腳本的任何對象的字符串。
我認為對於復雜的數據類型,您應該通過指定一個ToDB()方法來擴展它們,該方法擁有自己的實現來在DB中創建表,這樣它就變成了自動遞歸。
截至2016年(我認為),您可以使用Entity Framework 6 Code First從poco c#classes生成SQL模式,或使用Database First從sql生成c#代碼。 代碼優先到DB演練
對於復雜類型,您可以遞歸地將您遇到的每個類型轉換為它自己的表,然后嘗試管理外鍵關系。
您可能還希望預先指定將要或不將哪些類轉換為表。 對於要在數據庫中反映而不會使架構膨脹的復雜數據,可以為其他類型提供一個或多個表。 此示例使用多達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
有一個免費的應用程序,Schematrix從DB生成類,檢查是否反過來:) http://www.schematrix.com/products/schemacoder/download.aspx
嘗試DaoliteMappingTool for .net。 它可以幫助您生成類。 在此下載表格
另外......也許你可以使用一些工具,如Visio(不確定Visio是否這樣做,但我認為確實如此)將你的類反向工程為UML,然后使用UML生成DB Schema ...或者也許使用像http://www.tangiblearchitect.net/visual-studio/這樣的工具
我知道你正在尋找一個完整的持久層,但NHibernate的hbm2ddl任務可以做到這幾乎就像一個單行。
有一個NAnt任務可以調用它,這可能很有用。
亞音速也是另一種選擇。 我經常用它來生成映射到數據庫的實體類。 它有一個命令行實用程序,允許您指定表,類型和許多其他有用的東西
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.