代码之家  ›  专栏  ›  技术社区  ›  ileon

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

  •  3
  • ileon  · 技术社区  · 14 年前

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

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

    所以,问题是:

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

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

    另外,请注意,我希望您建议的解决方案参考.NET框架的2.0版,并基于传统实践(T-SQL代码如下: CREATE TABLE ... 尽管每个建议都受到欢迎。

    6 回复  |  直到 12 年前
        1
  •  2
  •   FishBasketGordo    12 年前

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

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

        2
  •  2
  •   Tom H    14 年前

    我不知道有什么工具,但是对于许多表来说,编写一个使用反射的小工具来获取所有属性,并使用定义了列名和类型的create table语句可能是值得的。一个完美的脚本是很难实现的,但是就像你问题中所说的,这可以给你一个很好的起点,然后调整字段类型和大小。

        3
  •  1
  •   SirDemon    14 年前

    有一个新的CTP出来了 "Code First" Entity Framework . 您可能可以使用它在代码编写多一点之后直接从代码生成数据库。

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

        4
  •  1
  •   Sruly    14 年前

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

    您可以使用t4或codedom,这可能比手动创建1000个表要花费更少的时间。

    编辑: 我第一次写答案时就忘了这一点。不久前我看到罗布·科内里的一个电影放映 亚音速简单收回 . 简单存储库允许您将一个对象插入到数据库中,如果没有表,它会为您创建一个对象。

    在这里观看视频 http://subsonicproject.com/docs/Using_SimpleRepository

        5
  •  1
  •   Dylan Beattie    14 年前

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

    下面是一个完整的例子,说明如何使用NHibernate和 Fluent NHibernate . 这是一个独立的C控制台应用程序,它将映射C业务对象的集合,并基于这些对象创建数据库模式。

    两个重要注意事项:

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

    这里是 程序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]
    
        6
  •  1
  •   EBarr labilbe    14 年前

    只是稍微扩展一下其他人所说的内容——大多数ORM类型的工具都具有模型优先功能。很像EF4,NHibernate和Telerik开放式接入,亚音速( http://www.subsonicproject.com/ )具有可以从类生成表的简单存储库模式。

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


    虽然你没有问,但我对你的数据访问需求很好奇。我们为三个主要任务雇佣关系数据库:持久性、有效的信息检索和声明性引用完整性(例如外键)。每节课只需创建一张桌子就可以完成一半的任务。

    您是否有大量的数据(即100千兆或多兆字节)?大量阅读?写很多东西?这些类有自然的主键吗?代理键?你的课程是否定义了彼此之间的关系(即 Employees 在工作 Factories )

    课堂上有很多领域吗?是否有任何元数据可以精确地指示数据类型,即不仅仅是 string Name 但那 Name 最多可以是80个字符,不能为空?你需要只存储英语还是使用需要扩展字符集的语言,比如普通话?如果您没有指示精度的方法,那么您的数据库将最终拥有非常宽的行(或者可能很宽)。许多数据库将最大行大小限制在8K-64K范围内。宽行影响读写性能。使用 text 字段可能会绕过页面大小限制,但会导致更昂贵的读取性能。

    与实现数据库结构一样重要的是索引它并使用引用完整性。类/表的数量是否随着时间的推移而增长?也许一个更抽象的、表更少的结构是合适的。

    就我的2c。希望有帮助。