Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Comment utiliser des annotations structurelles pour définir le type SQL sur Date dans la première approche du modèle

Annotation structurelle - sympa. C'est la première fois que j'entends parler de cette fonctionnalité mais elle fonctionne. Je viens d'essayer. Je vais essayer de l'expliquer un peu.

Les annotations structurelles ne sont que du xml aléatoire ajouté au fichier EDMX. Le fichier EDMX est en fait juste du XML qui a 4 parties - CSDL, MSL, SSDL et une partie liée au positionnement des éléments dans le concepteur.

  • CSDL décrit les entités et les associations entre entités (définies dans le concepteur)
  • SSDL décrit les tables et les relations
  • MSL décrit le mappage entre CSDL et SSDL

Si vous commencez par le modèle (vous souhaitez générer une base de données à partir de votre modèle), vous n'avez qu'une partie CSDL et SSDL et MSL seront générés par un processus automatique (modèles T4 exécutés dans le flux de travail) une fois que SSDL est créé, un autre modèle T4 générera Script SQL pour la création de la base de données.

L'annotation structurelle décrite dans le fil de discussion du forum MSDN lié est un indice. Vous placerez des annotations structurelles dans la partie CSDL de l'EDMX (vous devez ouvrir EDMX au format XML - cliquez sur le fichier dans l'explorateur de solutions et choisissez Ouvrir avec). Mon test CSDL décrit une entité utilisateur unique avec trois propriétés (l'entité est visible sur la capture d'écran plus tard dans la réponse) :

<!-- 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>

J'ai ajouté une définition d'espace de noms personnalisée dans Schema élément :xmlns:custom="http://tempuri.org/custom" et défini une annotation structurelle personnalisée pour CreatedAt propriété :

<Property Type="DateTime" Name="CreatedAt" Nullable="false">
   <custom:SqlType edmx:CopyToSSDL="true">Date</custom:SqlType>
</Property>

Le nom de l'espace de noms ou de l'élément utilisé pour l'annotation structurelle n'est pas important - c'est à vous de décider quels noms vous utilisez. La seule chose importante est edmx:CopyToSSDL="true" attribut. Cet attribut est reconnu par le modèle T4 utilisé pour la création SSDL et il prend simplement cet élément et le place dans SSDL. Le SSDL généré ressemble à :

<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>

Le seul point était de déplacer l'annotation structurelle vers SSDL. Toutes les annotations sont accessibles dans les métadonnées via une collection de valeurs de noms. Vous devez maintenant modifier le modèle T4 responsable de la génération du script SQL pour reconnaître cette annotation et utiliser la valeur définie dans l'annotation au lieu du type défini dans la propriété. Vous pouvez trouver le modèle dans :

C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\Extensions\Microsoft\Entity Framework Tools\DBGen\SSDLToSQL10.tt

Copiez le fichier de modèle dans un nouvel emplacement (afin de ne pas modifier l'original) et remplacez la création de table par défaut par ceci :

-- 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

Maintenant, le dernier point change le modèle utilisé pour la génération de script SQL. Ouvrez le fichier EDMX dans le concepteur et accédez aux propriétés du modèle (cliquez simplement quelque part dans le concepteur lorsque la fenêtre des propriétés est ouverte). Remplacez le modèle de génération DDL par le modèle que vous avez modifié.

Exécutez Générer la base de données à partir du modèle et il créera un script SQL contenant :

-- Creating table 'UsersSet'
CREATE TABLE [dbo].[UsersSet] (
    [Id]  int  IDENTITY(1,1) NOT NULL,
    [Login]  nvarchar(max)   NOT NULL,
    [CreatedAt]     Date   NOT NULL
);
GO

C'est probablement la fonctionnalité la plus avancée et la plus cachée d'EDMX que j'ai jamais vue. Les annotations associées aux modèles T4 personnalisés peuvent vous permettre de contrôler à la fois la classe et la génération SQL. Je peux imaginer l'utiliser pour définir par exemple des index de base de données ou des clés uniques lors de l'utilisation du modèle en premier ou ajouter de manière sélective des attributs personnalisés aux classes POCO générées.

La raison pour laquelle cela est si caché est qu'il n'y a pas de support d'outillage dans VS prêt à l'emploi pour l'utiliser.