Ответ 1
Структурная аннотация - хорошая. Это первый раз, когда я услышал об этой функции, но она работает. Я просто попробовал. Я попытаюсь немного объяснить это.
Структурные аннотации - это просто случайный xml, добавленный в файл EDMX. EDMX файл на самом деле просто XML, который имеет 4 части - CSDL, MSL, SSDL и часть, связанную с позиционирующими элементами в дизайнере.
- CSDL описывает сущности и ассоциации между сущностями (определенными в дизайнере)
- SSDL описывает таблицы и отношения
- MSL описывает сопоставление между CSDL и SSDL
Если вы сначала начнете с модели (вы хотите сгенерировать базу данных из своей модели), у вас будет только часть CSDL, и SSDL и MSL будут сгенерированы некоторым автоматическим процессом (шаблоны T4, выполняемые в рабочем процессе), когда SSDL будет создан еще один T4 шаблон создаст SQL script для создания базы данных.
Структурная аннотация, описанная в связанном потоке форума MSDN, является подсказкой. Вы разместите структурную аннотацию в CSDL часть EDMX (вы должны открыть EDMX как XML - щелкните файл в проводнике решений и выберите Open with). Мой тестовый CSDL описывает однопользовательский объект с тремя свойствами (сущность видна на снимке экрана позже в ответе):
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema xmlns="http://schemas.microsoft.com/ado/2008/09/edm"
xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration"
xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"
xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation"
xmlns:custom="http://tempuri.org/custom"
Namespace="Model" Alias="Self" >
<EntityContainer Name="ModelContainer" annotation:LazyLoadingEnabled="true">
<EntitySet Name="UsersSet" EntityType="Model.User" />
</EntityContainer>
<EntityType Name="User">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Type="Int32" Name="Id" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
<Property Type="String" Name="Login" Nullable="false" />
<Property Type="DateTime" Name="CreatedAt" Nullable="false">
<custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>
</EntityType>
</Schema>
</edmx:ConceptualModels>
Я добавил определение пользовательского пространства имен в элемент Schema
: xmlns:custom="http://tempuri.org/custom"
и определил пользовательскую структурную аннотацию для свойства CreatedAt
:
<Property Type="DateTime" Name="CreatedAt" Nullable="false">
<custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>
Название пространства имен или элемента, используемого для структурной аннотации, не имеет значения. Абсолютно зависит от вас, какие имена вы используете. Важно только атрибут edmx:CopyToSSDL="true"
. Этот атрибут распознается шаблоном T4, используемым для создания SSDL, и он просто берет этот элемент и помещает его в SSDL. Сгенерированный SSDL выглядит следующим образом:
<Schema Namespace="Model.Store" Alias="Self"
Provider="System.Data.SqlClient" ProviderManifestToken="2008"
xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator"
xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl">
<EntityContainer Name="ModelStoreContainer">
<EntitySet Name="UsersSet" EntityType="Model.Store.UsersSet" store:Type="Tables" Schema="dbo" />
</EntityContainer>
<EntityType Name="UsersSet">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Login" Type="nvarchar(max)" Nullable="false" />
<Property Name="CreatedAt" Type="datetime" Nullable="false">
<custom:SqlType xmlns:custom="http://tempuri.org/custom">Date</custom:SqlType>
</Property>
</EntityType>
</Schema>
Единственным моментом было перемещение структурной аннотации в SSDL. Все аннотации доступны в метаданных через некоторую коллекцию значений имен. Теперь вам нужно изменить шаблон T4, отвечающий за генерацию SQL script, чтобы распознать эту аннотацию и использовать значение, определенное в аннотации, вместо типа, определенного в свойстве. Шаблон можно найти в:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt
Скопируйте файл шаблона в новое место (чтобы вы не изменяли оригинал) и замените создание таблицы по умолчанию следующим образом:
-- Creating table '<#=tableName#>'
CREATE TABLE <# if (!IsSQLCE) {#>[<#=schemaName#>].<#}#>[<#=tableName#>] (
<#
for (int p = 0; p < entitySet.ElementType.Properties.Count; p++)
{
EdmProperty prop = entitySet.ElementType.Properties[p];
#>
[<#=Id(prop.Name)#>] <#
if (prop.MetadataProperties.Contains("http://tempuri.org/custom:SqlType"))
{
MetadataProperty annotationProperty = prop.MetadataProperties["http://tempuri.org/custom:SqlType"];
XElement e = XElement.Parse(annotationProperty.Value.ToString());
string value = e.Value.Trim();
#>
<#=value#> <# } else { #> <#=prop.ToStoreType()#> <# } #> <#=WriteIdentity(prop, targetVersion)#> <#=WriteNullable(prop.Nullable)#><#=(p < entitySet.ElementType.Properties.Count - 1) ? "," : ""#>
<#
}
#>
);
GO
Теперь последняя точка - это изменение шаблона, используемого для генерации SQL script. Откройте файл EDMX в дизайнере и перейдите к свойствам модели (просто щелкните где-нибудь в дизайнере, пока у вас открыто окно свойств). Измените шаблон генерации DDL на шаблон, который вы изменили.
Запустить генерацию базы данных из модели и создать SQL script, содержащий:
-- Creating table 'UsersSet'
CREATE TABLE [dbo].[UsersSet] (
[Id] int IDENTITY(1,1) NOT NULL,
[Login] nvarchar(max) NOT NULL,
[CreatedAt] Date NOT NULL
);
GO
Это, вероятно, самая передовая и скрытая функция EDMX, которую я еще видел. Аннотации вместе с пользовательскими шаблонами T4 могут обеспечить вам большой контроль над генерацией классов и SQL. Я могу представить, используя это, чтобы определить, например, индексы базы данных или уникальные ключи при первом использовании модели или выборочно добавлять некоторые настраиваемые атрибуты к сгенерированным классам POCO.
Причина, по которой это настолько скрыто, заключается в том, что для использования VS вне коробки нет поддержки инструментария.