Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

Abonnements

Comment ajouter des comportements à l’ObjectContext ?

Imaginons que l’on veuille ajouter un comportement à la classe ObjectContext dans le but de catché certaines exceptions par exemple. Si vous essayez de supprimer une entité déjà supprimée en base, vous ne voulez pas avoir d’exception. Dans la même idée, si vous supprimez une entité modifiée par un tiers, vous ne voulez pas non plus avoir d’exception.

Comme faire cela avec un code réutilisable ?

Une solution pourrait passer par une classe ExceptionHandlingObjectContext qui hérite d’ObjectContext et qui serait héritée par l’ObjectContext spécifique (ex : NorthwindEntities).

Cependant, on peut imaginer d’avoir également un TracingObjectContext qui serait ou non utiliser en fonction d’une configuration, en utilisant Unity par exemple, ce qui rend cette solution non viable.

Je vais donc opter pour une solution différente.

Je veux créer une classe CustomizableObjectContext qui ne connait pas les behaviors. Mon ObjectContext spécifique va en hériter et je vais ensuite lui renseigner mes behaviors en utilisant les delegates.

public class CustomizableObjectContext : ObjectContext
{
public CustomizableObjectContext(EntityConnection
connection)
:
base
(connection)
{
}
public CustomizableObjectContext(string
connectionString)
:
base
(connectionString)
{
}
protected CustomizableObjectContext(EntityConnection connection, string
defaultContainerName)
:
base
(connection, defaultContainerName)
{
}
protected CustomizableObjectContext(string connectionString, string
defaultContainerName)
:
base
(connectionString, defaultContainerName)
{
}

private List<Func<ObjectContext, SaveOptions, Func<SaveOptions, int>, int
>> _saveActions =
new List<Func<ObjectContext, SaveOptions, Func<SaveOptions, int>,int
>>();

public void AddSaveAction(Func<ObjectContext, SaveOptions, Func<SaveOptions, int>, int
> saveAction)
{
_saveActions.Add(saveAction);
}

public override int SaveChanges(SaveOptions
options)
{
Func<int, SaveOptions, int> saveAction = null
;
saveAction = (index, saveOptions) =>
{
if
(index == -1)
return base
.SaveChanges(saveOptions);
return _saveActions[index](this
, saveOptions, so => saveAction(index - 1, so));
};
return saveAction(_saveActions.Count - 1, options);
}
}

Maintenant je peux rajouter mon ExceptionHandling behavior :

public abstract class ObjectContextCustomizerBase<T> 
    where T : ObjectContextCustomizerBase<T>
{
    protected ObjectContext ObjectContext { get; set; }
   
    protected abstract int SaveChanges(ObjectContext context, SaveOptions options, Func<SaveOptions, int> baseSaveChanges);
}
public abstract class ObjectContextCustomizer<T>  : ObjectContextCustomizerBase<T>
    where T : ObjectContextCustomizer<T>, new()
{
    public static OC CreateObjectContext<OC>(OC objectContext)
        where OC : CustomizableObjectContext
    {
        objectContext.AddSaveAction(new T { ObjectContext = objectContext }.SaveChanges);
        return objectContext;
    }
}
public class ExceptionHandlerObjectContext : ObjectContextCustomizer<ExceptionHandlerObjectContext>
{
protected override int SaveChanges(ObjectContext context, SaveOptions options, Func<SaveOptions, int
> baseSaveChanges)
{
int
value = 0;
try
{
value = baseSaveChanges(options);
}
catch (OptimisticConcurrencyException
e)
{
bool canHandle = true
;
if
(e.StateEntries.Any() && e.StateEntries.Select(se =>
{
if (se.State != System.Data.EntityState
.Deleted)
return false
;
object
dbEntity;
if (ObjectContext.TryGetObjectByKey(se.EntityKey, out
dbEntity))
ObjectContext.ApplyOriginalValues(se.EntitySet.Name, dbEntity);
else
ObjectContext.Detach(se.Entity);
return true
;
}).TakeWhile(b => canHandle).Aggregate((b1, b2) => canHandle = b2))
// Aggregate for execute select on each of them
try
{
value = baseSaveChanges(options);
}
catch (System.Exception
e2)
{
throw e2;
}
else
throw e2;
}
return value;
}
}

Enfin, pour l’utiliser avec Unity, je peux utiliser le code suivant :

unityContainer.RegisterType<NorthwindEntities, NorthwindEntities>(new InjectionFactory(c => ExceptionHandlerObjectContext.CreateObjectContext(new NorthwindEntities())));
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é mardi 13 septembre 2011 21:36 par Matthieu MEZIL

Classé sous : , ,

Commentaires

Pas de commentaires

Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Les actualités de la semaine sur c2i.fr (14 mai - 20 mai) par Richard Clark le il y a 5 heures et 17 minutes

- Reactive Extensions : Consommer des services avec Rx Partie 3, les pièges à éviter par Léonard Labat le il y a 14 heures et 22 minutes

- SharePoint Blog Site, problème d’archives par Le Blog (Vert) d'Arnaud JUND le 05-20-2012, 13:09

- Soirée ALT.NET Mai - 3 présentations par #Rui le 05-18-2012, 11:59

- [ #SharePoint 2010][ #SQLServer 2012] AlwaysOn pour SharePoint (2/4) : Configuration (2e partie)… par Le blog de Patrick [MVP SharePoint] le 05-18-2012, 11:31

- Team Foundation Server 11: tous les trésors cachés du site d’équipe par Philess le 05-16-2012, 19:01

- [PowerShell 3] Télécharger et installer la documentation en ligne par Blog de SPBrouillet (Pierrick BROUILLET) le 05-16-2012, 17:36

- [#SharePoint 2010][#SQLServer 2012] AlwaysOn pour SharePoint (1/4) : Configuration (1ère partie)… par Le blog de Patrick [MVP SharePoint] le 05-16-2012, 12:10

- Job Day @MIC Brussels - .Net Developers on Mobile applications par Le Blog (Vert) d'Arnaud JUND le 05-15-2012, 20:26

- [SharePoint 2010] – SharePoint 2010, Windows (Server) 8 et des erreurs IIS sont dans une VM… par Blog de SPBrouillet (Pierrick BROUILLET) le 05-14-2012, 12:10