À l'origine je croyais que
context.Configuration.AutoDetectChangesEnabled = false;
désactive le suivi des modifications. Mais non. Actuellement, je dois utiliser AsNoTracking()
sur toutes mes requêtes LINQ (pour ma couche en lecture seule). Existe-t-il un paramètre global permettant de désactiver le suivi sur DbContext?
Étant donné que cette question ne contient pas de version EF spécifique, je souhaitais mentionner que dans EF Core, le comportement peut être configuré au niveau du contexte .
Vous pouvez également modifier le comportement de suivi par défaut au niveau du contexte niveau d'instance:
using (var context = new BloggingContext())
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var blogs = context.Blogs.ToList();
}
Qu'en est-il simplement d'exposer une méthode comme celle-ci sur votre contexte dérivé et de l'utiliser pour les requêtes:
public IQueryable<T> GetQuery<T>() where T : class {
return this.Set<T>().AsNoTracking();
}
Définir AsNoTracking
globalement n’est pas possible. Vous devez le définir pour chaque requête ou pour chaque ObjectSet
(pas DbSet
). Cette dernière approche nécessite l’utilisation de l’API ObjectContext
.
var objectContext = ((IObjectContextAdapter)dbContext).ObjectContext;
var set = objectContext.CreateObjectSet<T>();
set.MergeOption = MergeOption.NoTracking;
// And use set for queries
Vous pouvez faire quelque chose comme ça dans votre DbContext:
public void ObjectContext_OnObjectMaterialized(Object objSender, ObjectMaterializedEventArgs e)
{
Entry(e.Entity).State = EntityState.Detached;
}
Chaque fois qu'un objet est matérialisé par votre contexte, il sera détaché et ne sera plus suivi.
Mise à jour: Cela n'a pas vraiment fonctionné. Voir les commentaires!
Je déteste quand je cherche sur StackOverflow et la réponse est: "Vous ne pouvez pas!" ou "Vous pourriez le faire, mais seulement si vous modifiez complètement tous les appels que vous avez passés."
Réflexion quelqu'un? J'espérais que ce serait un paramètre DbContext. Mais comme ce n’est pas le cas, j’en ai fait une en utilisant la réflexion.
Cette petite méthode pratique définira AsNoTracking sur toutes les propriétés de type DbSet.
private void GloballySetAsNoTracking()
{
var dbSetProperties = GetType().GetProperties();
foreach (PropertyInfo pi in dbSetProperties)
{
var obj = pi.GetValue(this, null);
if (obj.GetType().IsGenericType && obj.GetType().GetGenericTypeDefinition() == typeof(DbSet<>))
{
var mi = obj.GetType().GetMethod("AsNoTracking");
mi.Invoke(obj, null);
}
}
}
Ajoutez-le à un constructeur DbContext surchargé.
public ActivationDbContext(bool proxyCreationEnabled, bool lazyLoadingEnabled = true, bool asNoTracking = true)
{
Configuration.ProxyCreationEnabled = proxyCreationEnabled;
Configuration.LazyLoadingEnabled = lazyLoadingEnabled;
if (asNoTracking)
GloballySetAsNoTracking();
}
Il utilise la réflexion, ce qui signifie que quelqu'un commentera rapidement qu'il s'agit d'un succès. Mais est-ce vraiment un succès? Cela dépend de votre cas d'utilisation.