zzzprojects / EntityFramework-Plus

Entity Framework Plus extends your DbContext with must-haves features: Include Filter, Auditing, Caching, Query Future, Batch Delete, Batch Update, and more
https://entityframework-plus.net/
MIT License
2.28k stars 318 forks source link

Error in cachekey when using GroupBy #138

Open diegobrum opened 7 years ago

diegobrum commented 7 years ago

Hi there!

When I use FromCache using follow EF instructions, Z throws a error.

Using


My code

var tags = ...; // Dynamic tags

query
    .Where(q => q.Active.Equals(1))
    .GroupBy(q => q.FederalState)
    .Select(q => q.Key)
    .Select(q => new FederalStateDto
    {
        Name = q
    })
    .CachedData(tags)
    .ToList();

Exception

System.ArgumentOutOfRangeException was unhandled by user code
  HResult=-2146233086
  Message=Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
  ParamName=index
  Source=System.Private.CoreLib
  StackTrace:
       at System.ThrowHelper.ThrowArgumentOutOfRange_IndexException()
       at Z.EntityFramework.Plus.InternalExtensions.CreateCommand(IQueryable source, RelationalQueryContext& queryContext)
       at Z.EntityFramework.Plus.QueryCacheManager.GetCacheKey(IQueryable query, String[] tags)
       at Z.EntityFramework.Plus.QueryCacheExtensions.FromCache[T](IQueryable`1 query, MemoryCacheEntryOptions options, String[] tags) 
JonathanMagnan commented 7 years ago

Hello @diegobrum ,

Thank you for reporting this issue.

I will check it when I will be back.

What exactly is doing the method CachedData?

Best Regards,

Jonathan

diegobrum commented 7 years ago

Sorry @JonathanMagnan

Where you see CachedData, read FromCache... I copy/past wrong code :/

JonathanMagnan commented 7 years ago

Hello @diegobrum ,

The issue happens because the query is not longer really a query.

When you do

.Select(q => new FederalStateDto
    {
        Name = q
    })

We try to retrieve the SQL Command generated to create the cache key, and we cannot find the query anymore.

By example, the cache will probably work if you move it here:

query
    .Where(q => q.Active.Equals(1))
    .GroupBy(q => q.FederalState)
    .FromCache(tags)
    .Select(q => q.Key)
    .Select(q => new FederalStateDto
    {
        Name = q
    })
    .ToList();

There are some other options that could work which doesn't require our library to generate the SQL Command for the cache key entry:

QueryCacheManager.UseFirstTagAsCacheKey = true;
QueryCacheManager.UseTagsAsCacheKey = true;

Let me know if you can use one of the solution above to solve your issue.

Best Regards,

Jonathan

diegobrum commented 7 years ago

Hi @JonathanMagnan

I used first option and works well. Thanks :)

But, when you say "We try to retrieve the SQL Command generated to create the cache key, and we cannot find the query anymore", I don't know, I feel it is incorrect, because I do this in a lot of parts of code (like bellow) and works well. I think the GroupBy clause is the bad guy in this story.

var tags = ... // dynamic tags

this._dbContext
    .City
    .Where(q => q.FederalState.Equals(federalState))
    .OrderBy(q => q.Name)
    .Select(q => q.Adapt<CityDto>())
    .FromCache(tags)
    .ToList();