2010-08-04 3 views
3

Мне нужно преобразовать набор классов C# (библиотеки классов) в таблицы SQL, которые будут использоваться SQL Server, чтобы данные могли храниться в базе данных и манипулировать через базу данных.Преобразование классов C# (библиотека классов) в SQL DDL (таблицы)

Проблема заключается в том, что число этих классов велико (более 1000 классов), и потребуется много времени для настройки такой схемы базы данных (таблицы, индексы, хранимые процедуры и т. Д.) - не укажите иерархии классов, которые мне нужно поддерживать.

Итак, вопрос:

Есть ли инструмент, который помог бы мне создать схему базы данных из библиотеки классов C#?

Я не ищу идеальный инструмент (но если есть такой инструмент, я был бы очень рад узнать), но и для инструмента, который поможет мне хотя бы создать отправную точку.

Пожалуйста, обратите внимание, что я бы предпочел, чтобы ваше предлагаемое решение ссылалось на версию 2.0 .NET Framework и основывалось на традиционной практике (код T-SQL вроде: CREATE TABLE ...), хотя каждое предложение приветствуется.

+0

Где вы работаете? Как бы я никогда не хотел там работать! 1000 столов, получайте удовольствие! – leppie

+0

Дизайн базы данных обычно реляционный, в отличие от ваших тысяч классов. Кроме того, как хранятся данные сегодня? Он не может все жить в памяти, может быть, вы можете конвертировать свою существующую базу данных? – Kobi

+2

@leppie: Иногда существует необходимость поддерживать существующий код. – ileon

ответ

2

Если вы можете использовать фреймворк Visual Studio 2010 v4.0, есть несколько новых возможностей для генерации скриптов с использованием «Первой модели» и структуры сущностей. Это явно не полезно для v2.0, но я думал, что стоит упомянуть.

Функция «Первая модель» позволяет создавать концептуальную (CSDL) модель в Entity Designer, а затем генерировать модель хранения (SSDL), а также сопоставление (MSL) между ними. Кроме того, мы также создаем сценарии T-SQL для создания базы данных для вас. Чтобы запустить мастер Model First, просто щелкните правой кнопкой мыши по поверхности Designer Entity и выберите «Generate Database from Model ...». Есть подробное сообщение в блоге here. Также проверьте this article.

+0

Ваше предложение приветствуется. Я просто не хочу заставлять клиентов использовать .NET 3.5 или 4.0. Но если я не могу найти решение для версии 2.0, я буду использовать решение на основе более поздней версии .NET. Спасибо. – ileon

+0

Я новичок в концепции Model First и недавно прочитал некоторые статьи, поэтому мои знания довольно ограничены. Я понимаю, что вы можете перейти от конструктора объектов к созданию табличных скриптов и т. Д., Но как вы собираетесь определять начальную модель для 1000+ классов/таблиц? Разве это не очень утомительный и ручной процесс? Если это так, то объем работы, выполняемой этим, будет сопоставим с написанием сценария create table с использованием пользовательского интерфейса для фактического создания таблицы с использованием студии управления. –

1

Существует новый CTP из "Code First" Entity Framework. Вы можете использовать это, чтобы сгенерировать свою базу данных непосредственно из кода после немного большего количества написания кода.

Это займет некоторое время с 1000 таблицами для создания.

+0

Я тоже думал об этой опции, но OP все равно придется сопоставлять эти объекты с существующими классами. Наверное, проще. – Kobi

+1

Спасибо за это, это даже лучше, чем Model First – Sruly

2

Я не знаю ни одного инструмента, но для многих таблиц, возможно, стоит написать небольшой инструмент с использованием Reflection, чтобы получить все свойства и выплюнуть создать инструкцию таблицы с именем столбца и определенным типом. Совершенный сценарий будет трудно достигнуть, но, как указано в вашем вопросе, это может дать вам очень хорошую отправную точку, чтобы затем настроить тип и размер поля.

+0

Это умная вещь. Спасибо за предложение. – ileon

1

Если структура класса является реляционной и относительно простой для преобразования в SQL Create Table или или EF-модель, возможно, вы можете написать собственный скрипт генерации кода для создания .edmx или SQL.

Вы можете использовать T4 или CodeDom, и, вероятно, потребуется намного меньше времени, чем вручную создать 1000 таблиц.

EDIT: Я забыл об этом, когда впервые написал свой ответ. Некоторое время назад я увидел скринкаст Роба Конира о Дозвуковой простой репозит. Простой репозиторий позволяет вам вставлять объект в БД, и если для него нет таблицы, он создает его для вас.

Проверьте видео здесь http://subsonicproject.com/docs/Using_SimpleRepository

+0

Интересно, спасибо. – ileon

1

Большинство объектно-реляционное отображение включает в себя возможность создания схемы базы данных на основе ваших отображенных классов.

Вот полный пример того, как вы это сделаете, используя NHibernate и Fluent NHibernate. Это автономное консольное приложение C#, которое отобразит коллекцию бизнес-объектов C# и создаст на их основе схему базы данных.

Два важных предостережений:

  1. NHibernate (и свободный 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<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] 
1

Просто расширить немного на то, что говорят другие - большинство инструментов ORM-типа имеют модели-первый потенциал. Подобно EF4, NHibernate и Telerik Open Access, Subsonic (http://www.subsonicproject.com/) имеет простой шаблон репозитория, который может генерировать таблицы из классов.

Альтернативный вариант здесь - написать простой инструмент, основанный на отражении, для прохождения ваших классов.


Хотя вы не спрашивали, мне любопытно, как ваши потребности в доступе к данным. Мы используем реляционные базы данных для трех основных задач: настойчивость, эффективное извлечение информации и декларативная ссылочная целостность (например, внешние ключи). Просто создание таблицы для каждого класса - это только половина битвы.

У вас большой объем данных (т. Е. 100 концертов или нескольких терабайт)? Много читает? много писем? У классов есть естественные первичные ключи? Суррогатные ключи? Разделяют ли ваши классы отношения между собой (т. Е. Employees работают в Factories).

У классов много полей? У вас есть метаданные, которые указывают типы данных с точностью, то есть не только string Name, но что Name может быть не более 80 символов и не может быть недействительным? Вам нужно хранить только английский язык или вы используете языки, требующие расширенных наборов символов, таких как Mandarin? Если у вас нет способа указать точность, ваша база данных будет иметь серьезные широкие ряды (или потенциально широкие). Многие базы данных ограничивают максимальный размер строки чем-то в диапазоне 8k-64k. Широкие ряды влияют на чтение &. Использование полей text может обойти ограничения по размеру страницы, но приведет к значительно более высокой производительности чтения.

Так же важно, как внедрять структуру базы данных, индексировать ее и использовать ссылочную целостность. Увеличивает ли количество классов/таблиц с течением времени? Возможно, более подходящей будет более абстрактная структура с меньшим количеством таблиц.

Просто мой 2c. Надеюсь, это поможет.

Смежные вопросы