将C#类(类库)转换为SQL DDL(表)

我必须将一组C#类(类库)转换为SQL Server使用的SQL表,以便数据可以存储在数据库中并通过数据库进行操作。

问题是这些类的数量很大(超过1000个类),并且需要很长时间来手动设置这样的数据库模式(表,索引,存储过程等) – 更不用说类层次结构了我需要保持。

所以,问题是:

有没有一个工具可以帮助我从C#类库创建数据库模式?

我不是在寻找完美的工具(但如果有这样的工具我会很高兴知道),但是对于一个能帮助我至少创造一个起点的工具。

请注意,我更倾向于您建议的解决方案来引用.NET Framework 2.0版,并且基于传统实践(T-SQL代码如: CREATE TABLE ... ),尽管每个建议都受到欢迎。

如果您可以使用Visual Studio 2010 v4.0框架,则可以使用“Model First”和entity framework生成脚本。 这显然对v2.0没有帮助,但我认为值得一提。

“模型优先”function允许您在实体设计器中设计概念(CSDL)模型,然后生成存储(SSDL)模型,以及它们之间的映射(MSL)。 此外,我们还生成T-SQL脚本以便为您创建数据库。 要运行Model First向导,只需右键单击Entity Designer表面,然后选择“从Model中生成数据库…”。 这里有一篇深入的博客文章。 另外,请查看此文章 。

我不知道任何工具,但对于那么多表,或许值得编写一个使用Reflection的小工具来获取所有属性并吐出创建表语句,并定义列名和类型。 一个完美的脚本很难实现,但正如你的问题所述,这可以为你提供一个非常好的起点,然后调整字段类型和大小。

“Code First”entity framework中有一个新的CTP。 在编写更多代码之后,您可以使用它直接从代码生成数据库。

创建1000个表还需要一段时间。

如果类结构是关系型的并且转换为SQL Create Table或EF模型相对简单,那么您可以编写自己的代码生成脚本来创建.edmx或SQL。

您可以使用T4或CodeDom,它可能比手动创建1000个表花费更少的时间。

编辑:当我第一次写回答时,我忘记了这一点。 前段时间我看到Rob Conery关于Subsonic Simple Repositroy的截屏video。 Simple Repository允许您将对象插入到DB中,如果没有表格,则为您创建一个对象。

在http://subsonicproject.com/docs/Using_SimpleRepository上查看video

大多数对象关系映射工具都包含一个基于映射类创建数据库模式的选项。

以下是使用NHibernate和Fluent NHibernate完成此操作的完整示例。 这是一个独立的C#控制台应用程序,它将映射C#业务对象的集合并基于它们创建数据库架构。

两个重要的警告:

  1. NHibernate(和Fluent NH)要求必须将业务对象的所有属性和方法声明为虚拟; 这可能需要修改一些现有代码。
  2. 不要对实时数据库运行此代码 – 默认情况下,它会为所有现有表生成DROP语句并重新创建它们。 它会杀死你的所有数据,这会让你伤心。 你被警告了。

这是program.cs 。 注意三个命名空间 – 一个包含程序本身,一个包含实体,另一个包含Fluent NHibernate的映射覆盖示例(如果您的对象不遵循内置映射约定,则很有用)

 using System; using System.Collections.Generic; using System.IO; using FluentNHibernate.Automapping; using FluentNHibernate.Automapping.Alterations; using FluentNHibernate.Cfg; using FluentNHibernate.Cfg.Db; using NHibernate; using NHibernate.Cfg; using NHibernate.Tool.hbm2ddl; using Schematica.Entities; namespace Schematica.ConsoleApp { class Program { const string SCHEMA_FILENAME = "schema.sql"; const string CONNECTION_STRING = "Data Source=spotgeek;Initial Catalog=dylanhax;Integrated Security=True"; public static void Main(string[] args) { if (File.Exists(SCHEMA_FILENAME)) File.Delete(SCHEMA_FILENAME); ConfigureNHibernate(CONNECTION_STRING, MapEntities); Console.WriteLine("Exported schema to " + (Path.GetFullPath(SCHEMA_FILENAME))); Console.ReadKey(false); } private static void MapEntities(MappingConfiguration map) { // Notice how we're constraining the auto-mapping to only map those entities // whose namespace ends with "Entities" - otherwise it'll try to // auto-map every class in the same assembly as Customer. map.AutoMappings.Add( AutoMap.AssemblyOf() .Where(type => type.Namespace.EndsWith("Entities")) .UseOverridesFromAssemblyOf()); } private static Configuration ConfigureNHibernate(string connectionString, Action mapper) { var database = Fluently.Configure().Database(MsSqlConfiguration.MsSql2005.ConnectionString(connectionString)); return (database.Mappings(mapper).ExposeConfiguration(ExportSchema).BuildConfiguration()); } private static void WriteScriptToFile(string schemaScript) { File.AppendAllText(SCHEMA_FILENAME, schemaScript); } private static void ExportSchema(Configuration config) { bool createObjectsInDatabase = false; new SchemaExport(config).Create(WriteScriptToFile, createObjectsInDatabase); } } } // This demonstrates how to override auto-mapped properties if your objects don't // adhere to FluentNH mapping conventions. namespace Schematica.Mappings { public class ProductMappingOverrides : IAutoMappingOverride { public void Override(AutoMapping map) { // This specifies that Product uses ProductCode as the primary key, // instead of the default Id field. map.Id(product => product.ProductCode); } } } // This is the namespace containing your business objects - the things you want to export to your database. namespace Schematica.Entities { public class Customer { public virtual int Id { get; set; } public virtual string Forenames { get; set; } public virtual string Surname { get; set; } } public class Product { public virtual Guid ProductCode { get; set; } public virtual string Description { get; set; } } public class Order { public virtual int Id { get; set; } private IList products = new List(); public virtual IList Products { get { return products; } set { products = value; } } public virtual Customer Customer { get; set; } } } 

以下是通过上面的代码导出到schema.sql的内容:

 if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FK952904EBD5E0278A]') AND parent_object_id = OBJECT_ID('[Product]')) alter table [Product] drop constraint FK952904EBD5E0278A if exists (select 1 from sys.objects where object_id = OBJECT_ID(N'[FKD1436656C882C014]') AND parent_object_id = OBJECT_ID('[Order]')) alter table [Order] drop constraint FKD1436656C882C014 if exists (select * from dbo.sysobjects where id = object_id(N'[Customer]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [Customer] if exists (select * from dbo.sysobjects where id = object_id(N'[Product]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [Product] if exists (select * from dbo.sysobjects where id = object_id(N'[Order]') and OBJECTPROPERTY(id, N'IsUserTable') = 1) drop table [Order] create table [Customer] ( Id INT IDENTITY NOT NULL, Forenames NVARCHAR(255) null, Surname NVARCHAR(255) null, primary key (Id) ) create table [Product] ( ProductCode UNIQUEIDENTIFIER not null, Description NVARCHAR(255) null, Order_id INT null, primary key (ProductCode) ) create table [Order] ( Id INT IDENTITY NOT NULL, Customer_id INT null, primary key (Id) ) alter table [Product] add constraint FK952904EBD5E0278A foreign key (Order_id) references [Order] alter table [Order] add constraint FKD1436656C882C014 foreign key (Customer_id) references [Customer] 

只是为了扩展其他人所说的内容 – 大多数ORM类型工具都具有模型优先function。 与EF4,NHibernate和Telerik Open Access非常相似,Subsonic( http://www.subsonicproject.com/ )具有可以从类生成表的简单存储库模式。

这里的另一个选择是编写一个简单的基于reflection的工具来遍历您的类。


虽然您没有问,但我对您的数据访问需求感到好奇。 我们为三个主要任务雇用关系数据库:持久性,有效的信息检索和声明性参照完整性(例如外键)。 仅仅为每个class级创建一个表只是成功的一半。

你有大量的数据(即100的演出或多太字节)? 很多读物? 很多写作? 这些类有自然的主键吗? 代理键? 您的class级是否定义了彼此之间的关系(即EmployeesFactories工作)。

课程有很多领域吗? 您是否有任何元数据表明数据类型具有精确性,即不仅仅是string NameName最多可以包含80个字符并且不可为空? 您是否只需要存储英语,或者您是否需要使用需要扩展字符集的语言,如普通话? 如果您没有指示精度的方法,那么您的数据库最终将会出现严重的行(或可能很宽)。 许多数据库将最大行大小限制在8k-64k范围内。 宽行影响读写性能。 使用text字段可能会限制页面大小限制,但会导致更高的读取性能。

与实现数据库结构一样重要的是索引它并使用参照完整性。 课程/表格的数量会随着时间的推移而增长吗? 也许更抽象的结构和更少的表格是合适的。

只是我的2c。 希望有所帮助。