Van*_*man 53 c# code-generation data-access
有没有人知道为给定类自动生成数据库表的方法?我不是在寻找一个完整的持久层 - 我已经有了一个我正在使用的数据访问解决方案,但我突然要从大量的类中存储大量信息而且我真的不想创建所有这些表都是手工制作.例如,给定以下类:
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
我期待以下SQL:
CREATE TABLE Foo
(
Property1 VARCHAR(500),
Property2 INT
)
Run Code Online (Sandbox Code Playgroud)
我也想知道你如何处理复杂的类型.例如,在之前引用的类中,如果我们将其更改为:
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; }
}
}
Run Code Online (Sandbox Code Playgroud)
我怎么能处理这个?
我已经看过尝试自己使用反射来自动生成数据库脚本来枚举每个类的属性,但它很笨重,复杂的数据类型让我感到难过.
Fly*_*wat 87
这真的很晚了,我只花了大约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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我把这些类放在一个程序集中来测试它:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
它生成了以下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
Run Code Online (Sandbox Code Playgroud)
一些进一步的想法...我考虑在你的类中添加一个属性,如[SqlTable],这样它只为你想要的类生成表.此外,这可以清理一吨,修复错误,优化(FK Checker是一个笑话)等等...只是为了让你开始.
Por*_*man 13
@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");
Run Code Online (Sandbox Code Playgroud)
和
// Create a PK Index for the table
Index index = new Index(newTable, "PK_TestTable");
index.IndexKeyType = IndexKeyType.DriPrimaryKey;
Run Code Online (Sandbox Code Playgroud)
如果您使用的是SQL 2005,VanOrman肯定会让SMO成为您解决方案的一部分.