samedi 18 décembre 2010

Exception lors de l'utilisation de l'incrémentation automatique avec Entity Framework et SQL Compact Edition : La solution

Environnement : C# , .NET 4.0 , Entity Framework 4 , SQL Server Compact Edition 3.5

Lors d'une brève expérience avec ces  technologies et ma première expérience avec SQL CE 3.5 j'ai eu la mauvaise surprise de me trouver devant l'impossibilité d'utiliser l'incrémentation automatique pour les clés primaires de type Int32 des entités définies dans EntityFramework
Voici une illustration du problème en adoptant une approche Model First ( EF -> SQLCE 3.5 )

Une entité Produit dont la clé est IdProduit , de type Int32 et incrémentée automatiquement ( StoredGenerationPattern = Identity )





En tenant compte de cette spécification , on n'a pas besoin d'attribuer un id à chaque entité produit crée.
Or avec SQL CE 3.5 la situation n'est pas la même.
En effet Le duo Entity Framework et SQL CE 3.5 ne nous permet pas d'utiliser directement cette fonction et génère une exception :

An error occured while updating the entries.See the inner exception for details.






Mais heureusement que les solutions existent :

On peut dans ce cas récupérer manuellement la prochaine valeur de la clé primaire ( et ainsi on réalise un auto - increment manuel ) :

Il suffit de créer une méthode de type Extension Methods : ( Les extension methods ou méthodes d'extension nous permettent d'ajouter des méthodes à un type de donnée particulier ) , pour plus d'informations :

Extension Methods sur MSDN ( EN )
Extension Methods sur MSDN ( FR )

Donc il suffit de créer une classe ExtensionMethods comme suit :


public static class ExtensionMethods
        {
            public static TResult NextId(this ObjectSet table, Expression> selector)
                where TSource : class
            {
                TResult lastId = table.Any() ? table.Max(selector) : default(TResult);

                if (lastId is int)
                {
                    lastId = (TResult)(object)(((int)(object)lastId) + 1);
                }

                return lastId;
            }
        }

Lorsqu'on a besoin de créer une entité produit il va falloir ajouter la ligne suivante pour affecter manuellement le prochain Id à notre entité nouvellement créée :


Produit produit = new Produit();
produit.IdProduit = ModelSingleton.getModel().ProduitSet.NextId(p => p.IdProduit);

1 : ModelSingleton.getModel() retourne le ModelContainer ( Le contexte )
2 : ProduitSet : regroupe les entités Produit.

Il faut aussi enlever le Stored Generation Pattern ( mettre none ou aucun ) ensuite régénérer la base de données à partir du modèle.

Ainsi on pourra effectuer nos opérations CRUD sans aucun problème.

3 commentaires: