VahidN / EFSecondLevelCache.Core

Entity Framework Core Second Level Caching Library
Apache License 2.0
326 stars 51 forks source link

Always returns first cached instance #53

Closed kooshanabedian closed 4 years ago

kooshanabedian commented 4 years ago

Summary of the issue

It seems that always the first cached result is returned.

Environment

.NET Core SDK version: 3.0.100-rc1-014190
Microsoft.EntityFrameworkCore version: 3.0.0-rc1.19456.14
EFSecondLevelCache.Core version: 2.6.4, [ 2.6.3 ]

Example code/Steps to reproduce:

pretty basic setup indeed, with redis cache.

await dbContext.Brokers_Requests
                .Where(o =>  o.Id == request.Id)
                .Cacheable()
                .FirstOrDefaultAsync();
kooshanabedian commented 4 years ago

Note that the Id property is located on an aggregate base class and inherited by other classes, if it matters in any way.

VahidN commented 4 years ago

I can't reproduce it. Try this sample. Using 2 different parameters will create 2 different cache-keys with different results from the cache: issue53

kooshanabedian commented 4 years ago

Indeed. Here is my sample for three different values for Id parameter. It generates three different records in Redis but all of them referencing the same hash.

Records:

1

1) 2

2) 3

3) 4

Data: 5

VahidN commented 4 years ago

You are using V2.6.3. Please update it to 2.6.4, because it considers ConstantExpression value's in final hash. In this case you won't see the same cache-keys.

kooshanabedian commented 4 years ago

You are right. my bad. updating to 2.64. fixes the issue for cases where I directly use DbContext. If I use some extension methods on DbContext to get some form of a repository pattern, I'm stuck again. But I guess that's some misuse on my part.

public static async Task<TEntity> GetFirstOrDefaultAsync<TEntity,TDbContext>(this TDbContext dbContext, Expression<Func<TEntity, bool>>? predicate = null,
                                                Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>>? orderBy = null,
                                                Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>>? include = null,
                                                bool disableTracking = true,
                                                CancellationToken cancellationToken = default(CancellationToken))
            where TEntity : class
            where TDbContext : CacheawareDbContext
        {
            IQueryable<TEntity> query = dbContext.Set<TEntity>();
            if (disableTracking)
            {
                query = query.AsNoTracking();
            }

            if (include != null)
            {
                query = include(query);
            }

            if (predicate != null)
            {
                query = query.Where(predicate);
            }

            if (orderBy != null)
            {
                    return await orderBy(query)
                            .Cacheable(cacheExpirationMode,timeSpan.Value)
                            .FirstOrDefaultAsync(cancellationToken);
            }
            else
            {
                    return await query
                            .Cacheable(cacheExpirationMode,timeSpan.Value)
                            .FirstOrDefaultAsync(cancellationToken);
            }
        }
VahidN commented 4 years ago

I tested your ext method and it works fine (creates 2 different cache-keys for 2 different inputs): issue53_@

kooshanabedian commented 4 years ago

Thank you for your help. I do very much appreciate it. I'm closing this now, since I couldn't track the core issue, which is obviously on my par.

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related problems.