Annotazione strutturale - bella. È la prima volta che sento parlare di questa funzione ma funziona. L'ho appena provato. Cercherò di spiegarlo un po'.
Le annotazioni strutturali sono solo XML casuali aggiunti al file EDMX. Il file EDMX è in effetti solo XML che ha 4 parti:CSDL, MSL, SSDL e parte relativa al posizionamento degli elementi nel designer.
- CSDL descrive entità e associazioni tra entità (definite nel designer)
- SSDL descrive tabelle e relazioni
- MSL descrive la mappatura tra CSDL e SSDL
Se inizi prima con il modello (vuoi generare un database dal tuo modello), hai solo una parte CSDL e sia SSDL che MSL verranno generati da alcuni processi automatici (modelli T4 eseguiti nel flusso di lavoro) una volta creato SSDL verrà generato un altro modello T4 Script SQL per la creazione di database.
L'annotazione strutturale descritta nel thread del forum MSDN collegato è un suggerimento. Si posizionerà l'annotazione strutturale nella parte CSDL dell'EDMX (è necessario aprire EDMX come XML - fare clic sul file in Esplora soluzioni e scegliere Apri con). Il mio CSDL di prova descrive una singola entità Utente con tre proprietà (l'entità è visibile nello screenshot più avanti nella risposta):
<!-- 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>
Ho aggiunto una definizione dello spazio dei nomi personalizzata in Schema
elemento:xmlns:custom="http://tempuri.org/custom"
e definita un'annotazione strutturale personalizzata per CreatedAt
proprietà:
<Property Type="DateTime" Name="CreatedAt" Nullable="false">
<custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>
Il nome dello spazio dei nomi o dell'elemento utilizzato per l'annotazione strutturale non è importante:dipende assolutamente da te quali nomi utilizzare. L'unica cosa importante è edmx:CopyToSSDL="true"
attributo. Questo attributo è riconosciuto dal modello T4 utilizzato per la creazione di SSDL e prende semplicemente questo elemento e lo inserisce in SSDL. L'SSDL generato assomiglia a:
<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>
L'unico punto era spostare l'annotazione strutturale su SSDL. Tutte le annotazioni sono accessibili nei metadati tramite una raccolta di valori di nome. Ora è necessario modificare il modello T4 responsabile della generazione dello script SQL per riconoscere questa annotazione e utilizzare il valore definito nell'annotazione anziché il tipo definito nella proprietà. Puoi trovare il modello in:
C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt
Copia il file modello in una nuova posizione (in modo da non modificare quello originale) e sostituisci la creazione della tabella predefinita con questo:
-- 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
Ora l'ultimo punto sta cambiando il modello utilizzato per la generazione di script SQL. Apri il file EDMX nel designer e vai alle proprietà del modello (fai clic da qualche parte nel designer mentre hai la finestra delle proprietà aperta). Cambia il modello di generazione DDL nel modello che hai modificato.
Esegui Genera database dal modello e creerà uno script SQL contenente:
-- Creating table 'UsersSet'
CREATE TABLE [dbo].[UsersSet] (
[Id] int IDENTITY(1,1) NOT NULL,
[Login] nvarchar(max) NOT NULL,
[CreatedAt] Date NOT NULL
);
GO
Questa è probabilmente la funzionalità più avanzata e nascosta di EDMX che abbia mai visto. Le annotazioni insieme ai modelli T4 personalizzati possono darti molto controllo sulla generazione di classi e SQL. Posso immaginare di usarlo per definire, ad esempio, indici di database o chiavi univoche quando si utilizza prima il modello o per aggiungere selettivamente alcuni attributi personalizzati alle classi POCO generate.
Il motivo per cui questo è così nascosto è che non c'è supporto per gli strumenti in VS pronto all'uso per usarlo.