Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

EDM : comment utiliser l’Horizontal Entity Splitting

Une des raisons pour lesquelles j’adore l’Entity Framework est la puissance de son mapping.

Beaucoup de développeurs pour ne pas dire la plus part n’en n’ont pas conscience.

Pour rappel, j’ai réalisé des videos (en anglais) sur le mapping.

Certains scenarii sont très souvent très utiles. D’autre le sont moins fréquemment. L’Horizontal Entity Splitting fait parti de ceux-ci. Cependant je vais essayer de démontrer dans ce post qu’il peut malgré tout être très utile dans certains cas.

Prenons Northwind : Products, Orders, OrderDetails. Les tables Orders et Products ont une primary key de type identity. La PK de OrderDetails correspond au couple ProductID, OrderID.

image_thumb[1]

Maintenant, imaginons que pour des raisons de traçabilité, on décide d’implémenter une suppression logique à la place d’une suppression physique.

Dans les tables Orders et Products, il me suffit de rajouter une colone IsDeleted de type bit non nullable.

Dans mon modèle, j’ajoute une condition IsDeleted = false pour filtrer automatiquement les entités.

image_thumb[4]

Maintenant on a un problème pour OrderDetails. En effet, le couple OrderID, ProductID doit maintenant être unique… seulement si IsDeleted est faux.

Pour cela, j’ajoute une nouvelle colone OrderID de type uniqueidentifier non nullable avec une default value égale à NewId() puis je définis la Primary Key sur celle-ci.

image_thumb[7]

Ensuite j’ajoute une contrainte d’unicité sur mon ancienne PK en utilisant un index de type Unique Key:

image_thumb[14]

Ensuite, j’utilise le script de création de la table pour créer une nouvelle table DeletedOrderDetails sans contrainte (à l’exception des foreign keys):

image_thumb[9]

CREATE TABLE [dbo].[DeletedOrderDetails](

      [OrderDetailID] [uniqueidentifier] NOT NULL,

      [OrderID] [int] NOT NULL,

      [ProductID] [int] NOT NULL,

      [UnitPrice] [money] NOT NULL,

      [Quantity] [smallint] NOT NULL,

      [Discount] [real] NOT NULL,

 CONSTRAINT [PK_DeletedOrderDetails] PRIMARY KEY CLUSTERED

(

      [OrderDetailID] ASC

)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

) ON [PRIMARY]

 

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails]  WITH NOCHECK ADD  CONSTRAINT [FK_DeletedOrderDetails_Orders] FOREIGN KEY([OrderID])

REFERENCES [dbo].[Orders] ([OrderID])

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails] CHECK CONSTRAINT [FK_DeletedOrderDetails_Orders]

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails]  WITH NOCHECK ADD  CONSTRAINT [FK_DeletedOrderDetails_Products] FOREIGN KEY([ProductID])

REFERENCES [dbo].[Products] ([ProductID])

GO

 

ALTER TABLE [dbo].[DeletedOrderDetails] CHECK CONSTRAINT [FK_DeletedOrderDetails_Products]

GO

Ensuite, je mets à jour mon edmx à partir de ma base afin de changer l’entité OrderDetail, la table [Order Details] dans le SSDL et le MSL entre eux.

Puis, je réduis l’Entity Key de OrderDetail à ma seule propriété OrderDetailID.

image_thumb[17]

Maintenant, du fait que j’ai une default value différente pour chaque DataRow, je peux affecter la metadata StoreGeneratedPattern à Identity sur cette propriété et cette colonne de façon à laisser la base générer la valeur (A noter que seule celui sur la colonne est utilisé dans ce cas). Je peux le faire avec le designer pour cette propriété mais seulement en modifiant le xml à la main pour la column.

image_thumb[19]image_thumb[21]

Ce que j’affectionne particulièrement avec cette approche est le fait qu’à l’exception des méthodes Delete je n’ai rien à changer dans mon code.

 

 

Maintenant, je vais m’occuper de la suppression.

Je créé un nouveau edmx NorthwindDeletion à partir de la base avec mes quatre tables.

Je veux avoir ce modèle :

image[44]_thumb

Au niveau de mes entités, je n’ai que faire des contraintes de la base. Je veux une façon simple de supprimer et restorer logiquement une entité et utiliser une propriété booléenne me parait idéal.

Pour avoir ce modèle, après avoir créé mon edmx, je vais supprimer l’entité DeletedOrderDetail en faisant attention à ne pas supprimer la table SSDL mappée dans le SSDL.

Ensuite, après avoir renommé les entités et mapper OrderDetail sur les deux tables d’OrderDetail, je me retrouve avec trois entités : ProductDeletion mappée sur la table Products, OrderDeletion mappée sur Orders et OrderDetailDeletion mappée sur [Order Details] ET DeletedOrderDetails.

Ensuite je vais ajouter une nouvelle propriété booléenne non nullable IsDeleted sur l’entité OrderDetailDeletion.

Maintenant je dois utiliser la propriété OrderDetailDeletion.IsDeleted pour identifier la table. C’est ce qu’on appelle l’Horizontal Entity Splitting. Malheureusement, ce scenario n’est toujours pas couvert par le designer de VS. Je vais donc le faire en modifiant le xml à la main :

image_thumb[26]

Voilà. Si OrderDetailDeletion.IsDeleted passe à true, ça impliquera un Delete From [Order Details] et un insert sur DeletedOrderDetails (et inversement si OrderDetailDeletion.IsDeleted passe à false) lors de l’appel à la méthode SaveChanges du context.

EF rocks!

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 :

Publié mercredi 8 septembre 2010 18:36 par Matthieu MEZIL

Commentaires

# re: EDM : comment utiliser l’Horizontal Entity Splitting @ jeudi 9 septembre 2010 10:12

Première réation à chaud : ouaou!

je pépars le  70-516... je crois que le mapping va finir par me faire mal à la tête.

Il y a vraiment trop de choses possibles avec.

JeremyJeanson

# re: EDM : comment utiliser l’Horizontal Entity Splitting @ samedi 11 septembre 2010 09:16

Justement c'est une des raisons qui fait de l'Entity Framework si puissant !

Matthieu MEZIL

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- [SharePoint] Les sessions TechDays 2012… par Le blog de Patrick [MVP SharePoint] le il y a 6 heures et 18 minutes

- TechDays Paris 2012 : Session pleinière jour 3 par Blog Technique de Romelard Fabrice le 02-09-2012, 11:01

- Mishra Reader : un lecteur RSS très Zune Style en Open Source ! par Cyril Sansus le 02-09-2012, 08:28

- [framework 4] Les Tasks et le Thread UI par Fathi Bellahcene le 02-09-2012, 00:33

- Workflow Foundation 3 a un pied dans la tombe par Blog de Jérémy Jeanson le 02-08-2012, 22:15

- TechDays Paris 2012 : Nouvelles tendances du poste de travail - Bring Your own PC par Blog Technique de Romelard Fabrice le 02-08-2012, 19:42

- TechDays Paris 2012 : System Center Service Manager 2012 Vue d’ensemble par Blog Technique de Romelard Fabrice le 02-08-2012, 17:32

- TechDays Paris 2012 : Pleinière second jour par Blog Technique de Romelard Fabrice le 02-08-2012, 16:23

- TechDays Paris 2012 : Retour d'expérience sur la mise en place d'un Cloud Privé par Blog Technique de Romelard Fabrice le 02-08-2012, 16:04

- TechDays Paris 2012 : Comment SharePoint a sauvé mes TechDays par Blog Technique de Romelard Fabrice le 02-07-2012, 23:59