В библиотеку добавлен 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#, но это стоит ли это включать в библиотеку.. к тому же все равно может попасться слово где неправильно множественное число образуется..