Adnotacja strukturalna - ładna. Po raz pierwszy słyszałem o tej funkcji, ale działa. Po prostu spróbowałem. Spróbuję to trochę wyjaśnić.
Adnotacje strukturalne to po prostu losowe pliki xml dodawane do pliku EDMX. Plik EDMX to w rzeczywistości po prostu XML, który składa się z 4 części - CSDL, MSL, SSDL i części związanej z pozycjonowaniem elementów w designerze.
- CSDL opisuje encje i powiązania między encjami (zdefiniowane w projektancie)
- SSDL opisuje tabele i relacje
- MSL opisuje mapowanie między CSDL i SSDL
Jeśli najpierw zaczniesz od modelu (chcesz wygenerować bazę danych ze swojego modelu), masz tylko część CSDL i zarówno SSDL, jak i MSL zostaną wygenerowane przez jakiś automatyczny proces (szablony T4 wykonywane w przepływie pracy) po utworzeniu SSDL zostanie wygenerowany inny szablon T4 Skrypt SQL do tworzenia bazy danych.
Podpowiedź stanowi adnotacja strukturalna opisana w linkowanym wątku na forum MSDN. Umieścisz adnotację strukturalną w części CSDL EDMX (musisz otworzyć EDMX jako XML - kliknij plik w eksploratorze rozwiązań i wybierz Otwórz za pomocą). Mój test CSDL opisuje pojedynczą encję użytkownika z trzema właściwościami (encja jest widoczna na zrzucie ekranu w dalszej części odpowiedzi):
<!-- 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>
Dodałem niestandardową definicję przestrzeni nazw w Schema
element:xmlns:custom="http://tempuri.org/custom"
i zdefiniowana niestandardowa adnotacja strukturalna dla CreatedAt
właściwość:
<Property Type="DateTime" Name="CreatedAt" Nullable="false">
<custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>
Nazwa przestrzeni nazw lub elementu użytego do adnotacji strukturalnej nie jest ważna - absolutnie od Ciebie zależy, jakich nazw użyjesz. Jedyną ważną rzeczą jest edmx:CopyToSSDL="true"
atrybut. Ten atrybut jest rozpoznawany przez szablon T4 używany do tworzenia SSDL i po prostu pobiera ten element i umieszcza go w SSDL. Wygenerowany SSDL wygląda następująco:
<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>
Jedynym punktem było przeniesienie adnotacji strukturalnej do SSDL. Wszystkie adnotacje są dostępne w metadanych za pośrednictwem kolekcji wartości nazw. Teraz musisz zmodyfikować szablon T4 odpowiedzialny za generowanie skryptu SQL, aby rozpoznawał tę adnotację i używał wartości zdefiniowanej w adnotacji zamiast typu zdefiniowanego we właściwości. Szablon znajdziesz w:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt
Skopiuj plik szablonu do nowej lokalizacji (aby nie modyfikować oryginalnej) i zastąp domyślne tworzenie tabeli następującym:
-- 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
Teraz ostatni punkt to zmiana szablonu używanego do generowania skryptów SQL. Otwórz plik EDMX w dizajnie i przejdź do właściwości modelu (wystarczy kliknąć gdzieś w dizajnie, gdy masz otwarte okno właściwości). Zmień szablon generowania DDL na zmodyfikowany szablon.
Uruchom Generuj bazę danych z modelu i utworzy skrypt SQL zawierający:
-- Creating table 'UsersSet'
CREATE TABLE [dbo].[UsersSet] (
[Id] int IDENTITY(1,1) NOT NULL,
[Login] nvarchar(max) NOT NULL,
[CreatedAt] Date NOT NULL
);
GO
Jest to prawdopodobnie najbardziej zaawansowana i ukryta funkcja EDMX, jaką do tej pory widziałem. Adnotacje wraz z niestandardowymi szablonami T4 zapewniają dużą kontrolę zarówno nad generowaniem klas, jak i SQL. Wyobrażam sobie użycie tego do zdefiniowania na przykład indeksów bazy danych lub unikalnych kluczy, gdy najpierw używasz modelu lub selektywnie dodawaj niestandardowe atrybuty do wygenerowanych klas POCO.
Powodem, dla którego jest to tak ukryte, jest to, że nie ma obsługi narzędzi w VS po wyjęciu z pudełka, aby tego użyć.