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

时间:2010-08-04 11:37:04

标签: c# .net sql sql-server vb.net

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

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

所以,问题是:

  

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

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

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

6 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

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

答案 3 :(得分:1)

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

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

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

点击此处观看视频 http://subsonicproject.com/docs/Using_SimpleRepository

答案 4 :(得分:1)

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

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

两个重要的警告:

  1. NHibernate(和Fluent NH)要求必须将业务对象的所有属性和方法声明为虚拟;这可能需要修改一些现有代码。
  2. 不要对实时数据库运行此代码,永远 - 默认情况下,它会为所有现有表生成DROP语句并重新创建它们。它会杀死你的所有数据,这会让你伤心。你被警告了。
  3. 这是 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<Customer>()
                    .Where(type => type.Namespace.EndsWith("Entities"))
                    .UseOverridesFromAssemblyOf<Customer>());
            }
    
            private static Configuration ConfigureNHibernate(string connectionString, Action<MappingConfiguration> 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<Product> {
            public void Override(AutoMapping<Product> 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<Product> products = new List<Product>();
            public virtual IList<Product> 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]
    

答案 5 :(得分:1)

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

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


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

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

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

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

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