How to combine Find () and AsNoTracking ()?

How to combine Find() with AsNoTracking() when creating queries in the EF context to prevent tracking of the returned object. This is what I can not do

  _context.Set<Entity>().AsNoTracking().Find(id); 

How can i do this? I am using EF version 6.

Note. I do not want to use SingleOrDefault() or Where . I just can't, because the Id parameter is generic and it's a struct , and I can't use the == operator for generics in this case.

+15
source share
4 answers

So instead of using AsNoTracking() you can Find() and then disconnect it from the context. I believe that this gives the same result as AsNoTracking() except for the extra cost of tracking an object. See EntityState for more information.

 var entity = Context.Set<T>().Find(id); Context.Entry(entity).State = EntityState.Detached; return entity; 

Change: This has some potential problems, if the context is not loaded with some relationships, then these navigation properties will not work, and you will be confused and upset why everything returns zero! See fooobar.com/questions/670707 / ... for more information. At the moment, in these repositories I am overriding the FindNoTracking() methods in my repositories that I need.

+17
source
 <context>.<Entity>.AsNoTracking().Where(s => s.Id == id); 

Find() does not make sense with AsNoTracking() , because Find should be able to return tracked objects without going to the database. The only option with AsNoTracking is either Where , or First or Single...

+6
source

Well, I think if you really want to do this, you can try creating your own expression yourself. I assume that you have a base entity class that is shared, and the one where the primary key property is generated. I called this class KeyedEntityBase<TKey> , TKey is the type of key (if you do not have such a class, that’s fine, the only thing I used for it is a general limitation). Then you can create an extension method like this to create the expression yourself:

 public static class Extensions { public static IQueryable<TEntity> WhereIdEquals<TEntity, TKey>( this IQueryable<TEntity> source, Expression<Func<TEntity, TKey>> keyExpression, TKey otherKeyValue) where TEntity : KeyedEntityBase<TKey> { var memberExpression = (MemberExpression)keyExpression.Body; var parameter = Expression.Parameter(typeof(TEntity), "x"); var property = Expression.Property(parameter, memberExpression.Member.Name); var equal = Expression.Equal(property, Expression.Constant(otherKeyValue)); var lambda = Expression.Lambda<Func<TEntity, bool>>(equal, parameter); return source.Where(lambda); } } 

And then you can use it like this (for an integer key type):

 context.Set<MyEntity>.AsNoTracking().WhereIdEquals(m=>m.Id, 9).ToList(); 
0
source

To repeat the behavior of Find and / or FindAsync , you can use:

  _context.EntitySet.FirstOrDefault(x => x.id == id).AsNoTracking(); 
0
source

Source: https://habr.com/ru/post/1241319/


All Articles