Strukturel anmærkning - flot. Det er første gang, jeg har hørt om denne funktion, men den virker. Jeg har lige prøvet det. Jeg vil prøve at forklare det lidt.
Strukturelle annotationer er blot tilfældige xml tilføjet til EDMX-fil. EDMX-fil er faktisk kun XML, som har 4 dele - CSDL, MSL, SSDL og en del relateret til positioneringselementer i designeren.
- CSDL beskriver enheder og associationer mellem enheder (defineret i designeren)
- SSDL beskriver tabeller og relationer
- MSL beskriver kortlægning mellem CSDL og SSDL
Hvis du starter med model først (du vil generere database fra din model), har du kun CSDL-del, og både SSDL og MSL vil blive genereret af en eller anden automatisk proces (T4-skabeloner eksekveret i workflow), når SSDL er oprettet, vil en anden T4-skabelon generere SQL-script til databaseoprettelse.
Strukturel annotation beskrevet i linket MSDN-forums tråd er et tip. Du vil placere strukturelle annoteringer i CSDL-delen af EDMX'en (du skal åbne EDMX som XML - klik på filen i Solution Explorer og vælg Åbn med). Min test-CSDL beskriver en enkelt brugerentitet med tre egenskaber (enheden er synlig på skærmbilledet senere i svaret):
<!-- 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>
Jeg har tilføjet en brugerdefineret navnerumsdefinition i Schema
element:xmlns:custom="http://tempuri.org/custom"
og defineret tilpasset strukturel annotation for CreatedAt
ejendom:
<Property Type="DateTime" Name="CreatedAt" Nullable="false">
<custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>
Navnet på det navneområde eller element, der bruges til strukturel annotering, er ikke vigtigt - det er helt op til dig, hvilke navne du bruger. Det eneste vigtige er edmx:CopyToSSDL="true"
attribut. Denne attribut genkendes af T4-skabelonen, der bruges til SSDL-oprettelse, og den tager bare dette element og placerer det i SSDL. Genereret SSDL ser sådan ud:
<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>
Det eneste punkt var at flytte den strukturelle annotation til SSDL. Alle annoteringer er tilgængelige i metadata gennem en eller anden navneværdiindsamling. Nu skal du ændre T4-skabelonen, der er ansvarlig for SQL-scriptgenerering, for at genkende denne annotation og bruge værdien defineret i annotationen i stedet for typen defineret i egenskaben. Du kan finde skabelonen i:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt
Kopier skabelonfilen til en ny placering (så du ikke ændrer den originale) og erstat oprettelse af standardtabel med denne:
-- 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
Nu er det sidste punkt at ændre skabelonen, der bruges til SQL-scriptgenerering. Åbn EDMX-filen i designeren og gå til modellens egenskaber (klik blot et sted i designeren, mens du har vinduet Egenskaber åbent). Skift DDL Generation Template til den skabelon, du har ændret.
Kør Generer database fra model og det vil oprette SQL-script, der indeholder:
-- Creating table 'UsersSet'
CREATE TABLE [dbo].[UsersSet] (
[Id] int IDENTITY(1,1) NOT NULL,
[Login] nvarchar(max) NOT NULL,
[CreatedAt] Date NOT NULL
);
GO
Dette er nok den mest avancerede og skjulte funktion af EDMX, jeg har set endnu. Annoteringer sammen med brugerdefinerede T4-skabeloner kan give dig meget kontrol over både klasse- og SQL-generering. Jeg kan forestille mig at bruge dette til at definere f.eks. databaseindekser eller unikke nøgler, når du bruger modellen først eller tilføje selektivt nogle brugerdefinerede attributter til genererede POCO-klasser.
Grunden til, at dette er så skjult, er, at der ikke er nogen værktøjsunderstøttelse i VS klar til at bruge dette.