EF : Comment faire de l'Entity Splitting avec des PK différentes ?
Imaginons que l'on veuille écrire une application dont le but est de gérer les stocks de produits en se basant sur Northwind sans avoir à les créer.
Dans cette optique, on souhaite avoir deux Entitysets : Product et Supplier avec Supplier en ReadOnly.
On aimerait également avoir une propriété CategoryName ReadOnly dans Product.
Comment faire cela avec un minimum de code ?
Pour commencer, il faut passer tous les set de Supplier à private. Pour cela, on modifiera l'attribut xml Setter.
Bien entendu, l'affectation du Setter à Private peut se faire via la fenêtre de properiétés du designer d'EDM (depuis VS 2008 SP1 Beta).
Ensuite, on va passer le set de la propriété Supplier de Product à private et passer la propriété (get + set) Products de Supplier à private.
On va également supprimer la propriété CategoryID de Product.
A ce niveau là, votre csdl doit ressembler à ça :
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema Namespace="NorthwindEFModel" Alias="Self" xmlns="http://schemas.microsoft.com/ado/2006/04/edm">
<EntityContainer Name="NorthwindEFEntities">
<EntitySet Name="Products" EntityType="NorthwindEFModel.Product" />
<EntitySet Name="Suppliers" EntityType="NorthwindEFModel.Supplier" />
<AssociationSet Name="FK_Products_Suppliers" Association="NorthwindEFModel.FK_Products_Suppliers">
<End Role="Suppliers" EntitySet="Suppliers" />
<End Role="Products" EntitySet="Products" />
</AssociationSet>
</EntityContainer>
<EntityType Name="Product">
<Key>
<PropertyRef Name="ProductID" />
</Key>
<Property Name="ProductID" Type="Int32" Nullable="false" />
<Property Name="ProductName" Type="String" Nullable="false" MaxLength="40" Unicode="true" FixedLength="false" />
<Property Name="QuantityPerUnit" Type="String" MaxLength="20" Unicode="true" FixedLength="false" />
<Property Name="UnitPrice" Type="Decimal" Precision="19" Scale="4" />
<Property Name="UnitsInStock" Type="Int16" />
<Property Name="UnitsOnOrder" Type="Int16" />
<Property Name="ReorderLevel" Type="Int16" />
<Property Name="Discontinued" Type="Boolean" Nullable="false" />
<NavigationProperty Name="Supplier" Relationship="NorthwindEFModel.FK_Products_Suppliers" FromRole="Products" ToRole="Suppliers" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
</EntityType>
<EntityType Name="Supplier">
<Key>
<PropertyRef Name="SupplierID" />
</Key>
<Property Name="SupplierID" Type="Int32" Nullable="false" />
<Property Name="CompanyName" Type="String" Nullable="false" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="ContactName" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="ContactTitle" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="Address" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="City" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="Region" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="PostalCode" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="Country" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="Phone" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="Fax" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<Property Name="HomePage" Type="String" Nullable="true" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />
<NavigationProperty Name="Products" Relationship="NorthwindEFModel.FK_Products_Suppliers" FromRole="Suppliers" ToRole="Products" a:SetterAccess="Private" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" a:GetterAccess="Private" />
</EntityType>
<Association Name="FK_Products_Suppliers">
<End Type="NorthwindEFModel.Supplier" Role="Suppliers" Multiplicity="0..1" />
<End Type="NorthwindEFModel.Product" Role="Products" Multiplicity="*" />
</Association>
</Schema>
</edmx:ConceptualModels>
Il nous reste maintenant à rajouter notre propriété CategoryName sur Product.
Comment faire cela. On peut bien sûr utiliser une vue à la place de la table Products et des procédures stockées ou même définir une vue ssdl avec des fonctions ssdl pour les opérations CUD (pour plus d'infos, voir mon article sur EDM). Cependant, nous sommes partisant du moindre effort ("Comment faire cela avec un minimum de code ?"). Pour cela, nous allons définir une vue ssdl réduite et nous allons utiliser l'EntitySplitting pour garder la partie de Product déjà générée par le designer. De plus cette approche nous évitera de coder les functions ssdl vu que l'on suppose que la propriété CategoryName de Product est en ReadOnly.
Pour cela, dans le SSDL, on va définir un nouveau EntitySet :
<EntitySet Name="ProductCategoryName" EntityType="NorthwindEFModel.Store.ProductCategoryName">
<DefiningQuery>
SELECT P.ProductID, C.CategoryName
FROM Products AS P
INNER JOIN Categories as C ON C.CategoryID = P.CategoryID
</DefiningQuery>
</EntitySet>
et un nouveau EntityType (toujours dans le SSDL) :
<EntityType Name="ProductCategoryName">
<Key>
<PropertyRef Name="ProductID" />
</Key>
<Property Name="ProductID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" />
<Property Name="CategoryName" Type="nvarchar" MaxLength="15" />
</EntityType>
Maintenant, on peut revenir en mode design et ajouter la propriété CategoryName (string avec setter à Private) et faire de l'EntitySplitting sur Product.

Et voila, c'est (déjà) fini. Vous avez un EntityType Supplier ReadOnly et un EntityType Product avec une propriété CategoryName ReadOnly.
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :