Using AsNoTracking() for Queries

Apr 15, 2014 at 10:28 PM
Hi,
Any plans for adding the AsNoTracking() functionality while executing a query?
_repository.Query(p => p.Id == productId).AsNoTracking()
It is useful sometimes to set your entities to be attached or not.

Thanks,
Coordinator
Apr 16, 2014 at 6:47 PM
We do not have any plans to implement AsNoTracking to the framework, however the framework is intended for ease of extensibility, meaning this should be fairly straight forward to implement.
Marked as answer by lelong37 on 4/16/2014 at 10:47 AM
Sep 24, 2014 at 7:25 PM
I second darioek's request as this prevents us from doing a simple query, alter, update flow. We ran into this specifically when we had to pull an object to determine if the current user had rights to alter it before doing an actual update.

This is probably the same issue this guy ran into:
https://genericunitofworkandrepositories.codeplex.com/discussions/561902
Coordinator
Sep 24, 2014 at 8:56 PM
Is the request here to add disable tracking to the API?

This can be accomplished by adding a repository method https://genericunitofworkandrepositories.codeplex.com/wikipage?title=Adding%20Custom%20Queries%20to%20Repository&referringTitle=Documentation, you have full access to IQueryable before it's executed on the Sql side.
Sep 24, 2014 at 10:40 PM
Edited Sep 24, 2014 at 10:40 PM
Thanks for the reply! I probably should not have used the word "prevent" in my comment as yes, there are definite ways around this, but they seem a bit messy so I was hoping we could get AsNoTracking added into your QueryFluent class and subsequently used in your repository Select method.

For example, say I want to select a "book" entity, include a few associated entities (maybe the library it's at), and use all this to determine in the "CheckoutBook" api method if the current user can check the book out before allowing them to do so. If I use the default service.query method to grab this info, the book will become "attached" and then when I wanted to update the book, like set the "DateLastCheckedOut" property, the update method will try to attach it again and we get an error as it is already attached.

We can get around this by selecting just the properties we need in the query instead of the entire book as that will prevent entity from attaching the book automatically or like you suggested, create a separate repository method to grab this info.

I'm not sure what best practice would be but having to create a new repository method just to grab a book and every other object I would ever need to grab without being tracked would seem like a lot of repeating? That and I would have to add my own call to dynamically "include" associated objects? Maybe pushing this logic into the repository does ultimately make sense but I suppose that's another discussion.

Alternatively and perhaps more elegant would be to modify the update method to check the context to see if it's already attached before trying to attach the same object again.

Thoughts?

Thanks,

PJ
Coordinator
Oct 5, 2014 at 10:32 PM
Edited Oct 5, 2014 at 10:33 PM
Thanks, tracking has already been implemented and will be in our next minor release.
Oct 5, 2014 at 10:39 PM
Cool. Any ideas when?
Coordinator
Oct 6, 2014 at 5:03 PM
Maybe end of week, after testing. BTW, there other repositories you prefer to use, please do, beauty of open source.
Oct 6, 2014 at 6:48 PM
Thanks you rock! Just want to add in case other's don't know that the repository has a Queryable method that just returns the dbset and you should be able just grab data old school including the ability to return a query .AsNoTracking() till the next version comes out.

I've tried a few repositories including an attempt at writing my own before we found and settled on this one, so thanks for putting in the work to create it for us all!

Cheers,

PJ
Nov 11, 2014 at 1:48 AM
I actually implemented this the other day.

To call it use the IQueryFluent.Tracking(false) or directly from the select depending on how you are calling these methods.

Query().Tracking(false);

In Repository.cs
    internal IQueryable<TEntity> Select(
            Expression<Func<TEntity, bool>> filter = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            List<Expression<Func<TEntity, object>>> includes = null,
            int? page = null,
            int? pageSize = null,
            bool tracking = true) // Added this line
        {
            IQueryable<TEntity> query = _dbSet;

            // And these three
            if (!tracking)
            {
                query = query.AsNoTracking();
            }


        internal async Task<IQueryable<TEntity>> SelectAsync(
            Expression<Func<TEntity, bool>> query = null,
            Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
            List<Expression<Func<TEntity, object>>> includes = null,
            int? page = null,
            int? pageSize = null,
            bool tracking = true) // Added this line
        {
            //See: Best Practices in Asynchronous Programming http://msdn.microsoft.com/en-us/magazine/jj991977.aspx
            return await Task.Run(() => Select(query, orderBy, includes, page, pageSize, tracking)).ConfigureAwait(false); // added tracking to call here as well
        }
In IQueryFluent.cs I added
        IQueryFluent<TEntity> Tracking(bool tracking);
In QueryFluent.cs:
        private bool _tracking = true;

...

        public IQueryFluent<TEntity> Tracking(bool tracking)
        {
            _tracking = tracking;
            return this;
        } 

        // Update these Select Calls to include tracking: _tracking
        public IQueryable<TEntity> Select() { return _repository.Select(_expression, _orderBy, _includes, tracking: _tracking); }

        public IQueryable<TResult> Select<TResult>(Expression<Func<TEntity, TResult>> selector) { return _repository.Select(_expression, _orderBy, _includes, tracking: _tracking).Select(selector); }

        public async Task<IQueryable<TEntity>> SelectAsync() { return await _repository.SelectAsync(_expression, _orderBy, _includes, tracking: _tracking); }

Feb 6, 2015 at 5:57 PM
Hi, was this implemented? I can´t find it in the code. Thanks.