В библиотеку добавлен T4 шаблон для генерации модели данных по базе данных. На данный момент сделана поддержка для Sybase и MS SQL.
Использовать следующим образом:
1. Копируем файлы шаблона из папки Source\Templates в свой проект.
2. Добавляем в проект новый файл с расширением tt.
3. Редактируем файл следующим образом:
С ConnectionString, думаю, всё ясно. В DataProviderAssembly указывается путь к сборке дата провайдера. Если сборка установлена в GAC, то вместо этого можно попробовать воспользоваться следующей директивой:
<#@ assembly name="Sybase.AdoNet2.AseClient" #>
Для MS SQL ничего этого делать не нужно. Т.е. шаблон будет выглядеть следующим образом:
В Namespace и DataContextName указываются соответсвенно namespace и имя класса, который будет выступать в качестве DataContext. К сожалению, из шаблонов нельзя просто доступиться к проекту студии и эти параметры нужно задавать вручную. В качестве альтернативы можно установить T4 Toolbox и изменить проект слудующим образом:
<#@ template language="C#v3.5" hostspecific="True" #>
<#@ output extension=".generated.cs" #>
<#@ include file="BLToolkit.ttinclude" #>
<#@ include file="BLT4Toolkit.ttinclude" #>
<#@ include file="MSSQL.ttinclude" #>
<#
ConnectionString = "Server=.;Database=BLToolkitData;Integrated Security=SSPI";
GenerateModel();
#>
Теперь эти параметры будут браться из проекта, но на компьютере должен быть установлен T4 Toolbox и работать шаблон будет только из под студии.
Работа шаблона состоит из двух этапов: чтение метаданных из БД и собственно рендеринг. После чтения метаданных их можно подредактировать по своему усмотрению. Следующий пример демонстрирует некоторые возможности:
<#@ template language="C#v3.5" #>
<#@ output extension=".generated.cs" #>
<#@ include file="BLToolkit.ttinclude" #>
<#@ include file="MSSQL.ttinclude" #>
<#
ConnectionString = "Server=.;Database=BLToolkitData;Integrated Security=SSPI";
Namespace = "Templates";
DataContextName = "DataModel";
// Важно! Этот метод нужно вызвать до начала работы с метаданными.
//
LoadMetadata();
// Меняем имя поля BinaryDataID таблицы BinaryData на ID.
//
Tables["BinaryData"].Columns["BinaryDataID"].MemberName = "ID";
// Меняем имя ассоциации FK_Employees_Employees таблицы Employees на ReportsToEmployee.
//
Tables["Employees"].ForeignKeys["FK_Employees_Employees"].MemberName = "ReportsToEmployee";
// Заменям имя поля на "ID", если это поле является первичным ключом и имеет имя ClassNameID.
// foreach (var t in Tables.Values)
foreach (var c in t.Columns.Values)
if (c.IsPrimaryKey && t.TableName + "ID" == c.ColumnName)
c.MemberName = "ID";
// Добавляем наследование entity классам от EntityBase<T>.
//
Usings.Add("BLToolkit.Common");
foreach (var t in Tables.Values)
t.BaseClassName = "EntityBase<" + t.ClassName + ">";
GenerateModel();
#>
В шаблоне имеется примитивная логика по разрешению нестандартных имён полей, типов и имён ассоциаций. Если эта логика не работает, то ручками можно подправить всё, что нужно.
Структура метаданных шаблона выглядит следующим образом:
Dictionary<string,Table> Tables = new Dictionary<string,Table>();
partial class Table
{
public string Owner;
public string TableName;
public string ClassName;
public string BaseClassName;
public bool IsView;
public List<string> Attributes = new List<string>();
public Dictionary<string,Column> Columns = new Dictionary<string,Column>();
public Dictionary<string,ForeignKey> ForeignKeys = new Dictionary<string,ForeignKey>();
}
partial class Column
{
public int ID;
public string ColumnName;
public string MemberName;
public bool IsNullable;
public bool IsIdentity;
public string Type;
public bool IsClass;
public DbType DbType;
public SqlDbType SqlDbType;
public int PKIndex = -1;
public List<string> Attributes = new List<string>();
public bool IsPrimaryKey { get { return PKIndex >= 0; } }
}
enum AssociationType
{
Auto,
OneToOne,
OneToMany,
ManyToOne,
}
partial class ForeignKey
{
public string KeyName;
public string MemberName;
public Table OtherTable;
public List<Column> ThisColumns = new List<Column>();
public List<Column> OtherColumns = new List<Column>();
public ForeignKey BackReference;
public AssociationType AssociationType;
}
При желании, манипуляции с метаданными можно оформить в виде отдельного файла как это сделано для атрибутов WCF:
Этот шаблон добавляет атрибуты DataContract классам и DataMember свойствам модели и выглядит следующим образом:
<#
{
var wcfPrevBeforeGenerateModel = BeforeGenerateModel;
BeforeGenerateModel = tt =>
{
wcfPrevBeforeGenerateModel(tt);
Usings.Add("System.Runtime.Serialization");
foreach (var t in Tables.Values)
t.Attributes.AddRange(new[] { "Serializable", "DataContract" });
foreach (var t in Tables.Values)
foreach (var c in t.Columns.Values)
c.Attributes.Add("DataMember");
};
}
#>
Добавить поддержку остальных провайдеров не проблема, но нужно разбираться с тем как читать из низ метаданные. Если у кого-то есть подобная информация, то добавить другие провайдеры будет проще простого.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Добавить поддержку остальных провайдеров не проблема, но нужно разбираться с тем как читать из низ метаданные. Если у кого-то есть подобная информация, то добавить другие провайдеры будет проще простого. DbLinq знает, у них даже свой инструмент есть, DbMetal (аналог Sqlmetal). Можно подглядеть, или даже заюзать, там вроде бы есть апи к метаданным..
Здравствуйте, Legion13, Вы писали:
IT>>Добавить поддержку остальных провайдеров не проблема, но нужно разбираться с тем как читать из низ метаданные. Если у кого-то есть подобная информация, то добавить другие провайдеры будет проще простого. L>DbLinq знает, у них даже свой инструмент есть, DbMetal (аналог Sqlmetal). Можно подглядеть, или даже заюзать, там вроде бы есть апи к метаданным..
Посмотрим. Спасибо за наводку.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>В библиотеку добавлен T4 шаблон для генерации модели данных по базе данных. На данный момент сделана поддержка для Sybase и MS SQL.
Не планируется ли чтение метаданных перенести из T4 шаблонов в тулкит? Мне бы это очень пригодилось.
Здравствуйте, Ziaw, Вы писали:
IT>>В библиотеку добавлен T4 шаблон для генерации модели данных по базе данных. На данный момент сделана поддержка для Sybase и MS SQL.
Z>Не планируется ли чтение метаданных перенести из T4 шаблонов в тулкит? Мне бы это очень пригодилось.
В принципе, можно. Надо только решить куда это лучше затолкать.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, AndrewVK, Вы писали:
Z>>Не планируется ли чтение метаданных перенести из T4 шаблонов в тулкит? Мне бы это очень пригодилось.
AVK>Поищи, вопрос уже обсуждался. Вкратце — все зависит от того, зачем тебе эти метаданные нужны.
Для того же что и в шаблонах. Генерации модели по базе, только макросами в немерле. Сейчас я использую янусовский читатель метаданных. Только типы колонок заменил на тулкитовские, они поудобнее. Если чтение метаданых будет в тулките — для работы со схемой мне останется только генерация DDL, которую можно и переписать с нуля.
Здравствуйте, Ziaw, Вы писали:
Z>Для того же что и в шаблонах. Генерации модели по базе, только макросами в немерле. Сейчас я использую янусовский читатель метаданных. Только типы колонок заменил на тулкитовские, они поудобнее. Если чтение метаданых будет в тулките — для работы со схемой мне останется только генерация DDL, которую можно и переписать с нуля.
Дело в том, что метаданные разных БД отличаются очень сильно, намного сильнее SQL. Вот те же автоинкрементные поля, к примеру. В янусе там хитрые хаки используются, но для библиотеки это не очень хорошо.
... << RSDN@Home 1.2.0 alpha 4 rev. 1474 on Windows 7 6.1.7600.0>>
Здравствуйте, AndrewVK, Вы писали:
Z>>Для того же что и в шаблонах. Генерации модели по базе, только макросами в немерле. Сейчас я использую янусовский читатель метаданных. Только типы колонок заменил на тулкитовские, они поудобнее. Если чтение метаданых будет в тулките — для работы со схемой мне останется только генерация DDL, которую можно и переписать с нуля.
AVK>Дело в том, что метаданные разных БД отличаются очень сильно, намного сильнее SQL.
Да, я в курсе.
AVK>Вот те же автоинкрементные поля, к примеру. В янусе там хитрые хаки используются, но для библиотеки это не очень хорошо.
В янусе, афайк, используются хаки для эмуляции таких полей там где их нет. Это действительно геморой.
Здравствуйте, AndrewVK, Вы писали:
AVK>Ну вот где то поля, где то генераторы, где то функция специяльная. Полный разброд и шатание. AVK>Так вот и вопрос, что с этим делать.
С чем? С чтением метаданных? Да ничего, если база умеет автоинкрементные колонки флаг IsIdentity у них будет выставлятьтся, если нет — нет.
Или с генерацией ключей? Тут в принципе можно сделать по образу гиберенейта, там в маппинге указывается генератор для пк.
Генераторы достаточно простые, часть делает запрос перед вставкой в БД, часть после, часть получает в качестве резульата инсерта, часть генерит ключ без участия БД.
Все что нужно — атрибут для указания генератора и отдавать генератору запрос и объект перед вставкой и после вставки.
Некоторые генераторы поддерживаются частью доступных БД, некоторые всеми. Есть специальный генератор native, который использует штатный генератор конкретной БД. Пользователь уже сам выбирает какой использовать.
Здравствуйте, IT, Вы писали:
IT>В библиотеку добавлен T4 шаблон для генерации модели данных по базе данных. На данный момент сделана поддержка для Sybase и MS SQL.
Очень здорово сделано! А что насчет WCFAttributes? Я добавил этот файл в инклюды, но что-то [DataContract] и [DataMember] атрибуты не появились...
<#@ template language="C#v3.5" #>
<#@ output extension=".generated.cs" #>
<#@ include file="BLToolkit.ttinclude" #>
<#@ include file="WCFAttributes.ttinclude" #>
<#@ include file="MSSQL.ttinclude" #>
Здравствуйте, IT, Вы писали:
IT>Как это должно работать?
Да просто добавлять постфикс "s" к именам свойств, представляющих таблицы сущностей — в примере ниже это TdxEvents, TdxEventTypes etc.
public partial class DataModel : DbManager
{
public Table<TdxEvent> TdxEvents { get { return this.GetTable<TdxEvent>(); } }
public Table<TdxEventType> TdxEventTypes { get { return this.GetTable<TdxEventType>(); } }
public Table<TdxParameter> TdxParameters { get { return this.GetTable<TdxParameter>(); } }
public Table<TdxParameterValue> TdxParameterValues { get { return this.GetTable<TdxParameterValue>(); } }
public Table<TdxSession> TdxSessions { get { return this.GetTable<TdxSession>(); } }
}
Здравствуйте, Andy77, Вы писали:
A>Да просто добавлять постфикс "s" к именам свойств, представляющих таблицы сущностей — в примере ниже это TdxEvents, TdxEventTypes etc.
Как быть с именами вроде Boss и City?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Как быть с именами вроде Boss и City?
А также Child-Children и т.д.
В принципе есть готовые классы-конвертеры на C#, но это стоит ли это включать в библиотеку.. к тому же все равно может попасться слово где неправильно множественное число образуется..
Здравствуйте, MozgC, Вы писали:
MC>В принципе есть готовые классы-конвертеры на C#, но это стоит ли это включать в библиотеку.. к тому же все равно может попасться слово где неправильно множественное число образуется..
Если есть гововые классы в виде исходников с открытой лицензией, то включить не проблема. На счёт 100% покрытия речи нет, 90-95 уже хорошо, остальное можно и ручками в шаблоне поменять.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Если есть гововые классы в виде исходников с открытой лицензией, то включить не проблема. На счёт 100% покрытия речи нет, 90-95 уже хорошо, остальное можно и ручками в шаблоне поменять.
Ну так добавление "s" или "es", в зависимости от последней буквы, как раз покроет 95% всех случаев, тем более что в IT уже появилась традиция формировать слова неправильно (indexes уже прижившееся слово, хотя должно быть indices)
Здравствуйте, Andy77, Вы писали:
IT>>Если есть гововые классы в виде исходников с открытой лицензией, то включить не проблема. На счёт 100% покрытия речи нет, 90-95 уже хорошо, остальное можно и ручками в шаблоне поменять. A>Ну так добавление "s" или "es", в зависимости от последней буквы, как раз покроет 95% всех случаев, тем более что в IT уже появилась традиция формировать слова неправильно (indexes уже прижившееся слово, хотя должно быть indices)
Не верю, что такой алгоритм ещё не написан
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, IT, Вы писали:
IT>Если есть гововые классы в виде исходников с открытой лицензией, то включить не проблема. На счёт 100% покрытия речи нет, 90-95 уже хорошо, остальное можно и ручками в шаблоне поменять.
Тогда вот несколько ссылок, первые 2 на C#, вторые 2 на java:
Здравствуйте, IT, Вы писали:
IT>Не верю, что такой алгоритм ещё не написан
Уже даже включен почти в фреймворк (4-й), смотреть
System.Data.Entity.Design.PluralizationServices.PluralizationService
он вроде как умный и даже расширяемый.
Вот только то, что он находится в System.Data.Entity.Design.dll сводит на нет все его преимущества и возможности использования
Здравствуйте, andrex, Вы писали: A>Вот только то, что он находится в System.Data.Entity.Design.dll сводит на нет все его преимущества и возможности использования
Сборка MySql.Data.dll должна быть установлена в GAC'е. Если она не установлена в GAC'е, то нужно задать путь к сборке в свойстве DataProviderAssembly, подробнее здесь: T4 templates for data model generating