protected async Task <TResult> GetCachedQueryResultAsync <TResult>(ICommandOptions options, string cachePrefix = null, string cacheSuffix = null) { if (IsCacheEnabled && (options.ShouldUseCache() || options.ShouldReadCache()) && !options.HasCacheKey()) { throw new ArgumentException("Cache key is required when enabling cache.", nameof(options)); } if (!IsCacheEnabled || !options.ShouldReadCache() || !options.HasCacheKey()) { return(default);
public virtual async Task <T> GetByIdAsync(Id id, ICommandOptions options = null) { if (String.IsNullOrEmpty(id.Value)) { return(null); } T hit = null; if (IsCacheEnabled && options.ShouldReadCache()) { hit = await Cache.GetAsync <T>(id, default).AnyContext(); } bool isTraceLogLevelEnabled = _logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace); if (hit != null) { if (isTraceLogLevelEnabled) { _logger.LogTrace("Cache hit: type={ElasticType} key={Id}", ElasticType.Name, id); } return(hit); } if (!HasParent || id.Routing != null) { var request = new GetRequest(GetIndexById(id), ElasticType.Name, id.Value); if (id.Routing != null) { request.Routing = id.Routing; } var response = await _client.GetAsync <T>(request).AnyContext(); if (isTraceLogLevelEnabled) { _logger.LogTrace(response.GetRequest()); } hit = response.Found ? response.ToFindHit().Document : null; } else { // we don't have the parent id so we have to do a query // TODO: Ensure this is find one query is not cached. var findResult = await FindOneAsync(NewQuery().Id(id)).AnyContext(); if (findResult != null) { hit = findResult.Document; } } if (hit != null && IsCacheEnabled && options.ShouldUseCache()) { await Cache.SetAsync(id, hit, options.GetExpiresIn()).AnyContext(); } return(hit); }
public virtual async Task <FindHit <T> > FindOneAsync(IRepositoryQuery query, ICommandOptions options = null) { options = ConfigureOptions(options.As <T>()); if (IsCacheEnabled && (options.ShouldUseCache() || options.ShouldReadCache()) && !options.HasCacheKey()) { throw new ArgumentException("Cache key is required when enabling cache.", nameof(options)); } var result = IsCacheEnabled && options.ShouldReadCache() && options.HasCacheKey() ? await GetCachedFindHit(options).AnyContext() : null; if (result != null) { return(result.FirstOrDefault()); } await OnBeforeQueryAsync(query, options, typeof(T)).AnyContext(); await RefreshForConsistency(query, options).AnyContext(); var searchDescriptor = (await CreateSearchDescriptorAsync(query, options).AnyContext()).Size(1); var response = await _client.SearchAsync <T>(searchDescriptor).AnyContext(); if (response.IsValid) { _logger.LogRequest(response, options.GetQueryLogLevel()); } else { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(FindHit <T> .Empty); } _logger.LogErrorRequest(response, "Error while finding document"); throw new ApplicationException(response.GetErrorMessage(), response.OriginalException); } result = response.Hits.Select(h => h.ToFindHit()).ToList(); if (IsCacheEnabled && options.ShouldUseCache()) { await AddDocumentsToCacheAsync(result, options).AnyContext(); } return(result.FirstOrDefault()); }
public virtual async Task <T> GetByIdAsync(Id id, ICommandOptions options = null) { if (String.IsNullOrEmpty(id.Value)) { return(null); } options = ConfigureOptions(options.As <T>()); if (IsCacheEnabled && options.HasCacheKey()) { throw new ArgumentException("Cache key can't be set when calling GetById"); } if (IsCacheEnabled && options.ShouldReadCache()) { var value = await GetCachedFindHit(id).AnyContext(); if (value?.Document != null) { _logger.LogTrace("Cache hit: type={EntityType} key={Id}", EntityTypeName, id); return(ShouldReturnDocument(value.Document, options) ? value.Document : null); } } FindHit <T> findHit; if (!HasParent || id.Routing != null) { var request = new GetRequest(ElasticIndex.GetIndex(id), id.Value); if (id.Routing != null) { request.Routing = id.Routing; } var response = await _client.GetAsync <T>(request).AnyContext(); _logger.LogRequest(response, options.GetQueryLogLevel()); findHit = response.Found ? response.ToFindHit() : null; } else { // we don't have the parent id so we have to do a query // TODO: Ensure this find one query is not cached. findHit = await FindOneAsync(NewQuery().Id(id), options.Clone().DefaultCacheKey(id)).AnyContext(); } if (IsCacheEnabled && options.ShouldUseCache()) { await AddDocumentsToCacheAsync(findHit ?? new FindHit <T>(id, null, 0), options).AnyContext(); } return(ShouldReturnDocument(findHit?.Document, options) ? findHit?.Document : null); }
public virtual async Task <CountResult> CountAsync(IRepositoryQuery query, ICommandOptions options = null) { options = ConfigureOptions(options.As <T>()); CountResult result; if (IsCacheEnabled && options.ShouldReadCache()) { result = await GetCachedQueryResultAsync <CountResult>(options, "count").AnyContext(); if (result != null) { return(result); } } await OnBeforeQueryAsync(query, options, typeof(T)).AnyContext(); await RefreshForConsistency(query, options).AnyContext(); var searchDescriptor = await CreateSearchDescriptorAsync(query, options).AnyContext(); searchDescriptor.Size(0); var response = await _client.SearchAsync <T>(searchDescriptor).AnyContext(); if (response.IsValid) { _logger.LogRequest(response, options.GetQueryLogLevel()); } else { if (response.ApiCall.HttpStatusCode.GetValueOrDefault() == 404) { return(new CountResult()); } _logger.LogErrorRequest(response, "Error getting document count"); throw new ApplicationException(response.GetErrorMessage(), response.OriginalException); } result = new CountResult(response.Total, response.ToAggregations()); if (IsCacheEnabled && options.ShouldUseCache()) { await SetCachedQueryResultAsync(options, result, "count").AnyContext(); } return(result); }
protected async Task <TResult> GetCachedQueryResultAsync <TResult>(ICommandOptions options, string cachePrefix = null, string cacheSuffix = null) { if (!IsCacheEnabled || options == null || !options.ShouldReadCache() || !options.HasCacheKey()) { return(default(TResult)); } string cacheKey = cachePrefix != null ? cachePrefix + ":" + options.GetCacheKey() : options.GetCacheKey(); if (!String.IsNullOrEmpty(cacheSuffix)) { cacheKey += ":" + cacheSuffix; } var result = await Cache.GetAsync <TResult>(cacheKey, default(TResult)).AnyContext(); _logger.Trace(() => $"Cache {(result != null ? "hit" : "miss")}: type={ElasticType.Name} key={cacheKey}"); return(result); }
public async Task <IReadOnlyCollection <T> > GetByIdsAsync(Ids ids, ICommandOptions options = null) { var idList = ids?.Distinct().Where(i => !String.IsNullOrEmpty(i)).ToList(); if (idList == null || idList.Count == 0) { return(EmptyList); } if (!HasIdentity) { throw new NotSupportedException("Model type must implement IIdentity."); } var hits = new List <T>(); if (IsCacheEnabled && options.ShouldReadCache()) { var cacheHits = await Cache.GetAllAsync <T>(idList.Select(id => id.Value)).AnyContext(); hits.AddRange(cacheHits.Where(kvp => kvp.Value.HasValue).Select(kvp => kvp.Value.Value)); } var itemsToFind = idList.Except(hits.OfType <IIdentity>().Select(i => (Id)i.Id)).ToList(); if (itemsToFind.Count == 0) { return(hits.AsReadOnly()); } var multiGet = new MultiGetDescriptor(); foreach (var id in itemsToFind.Where(i => i.Routing != null || !HasParent)) { multiGet.Get <T>(f => { f.Id(id.Value).Index(GetIndexById(id)).Type(ElasticType.Name); if (id.Routing != null) { f.Routing(id.Routing); } return(f); }); } var multiGetResults = await _client.MultiGetAsync(multiGet).AnyContext(); _logger.Trace(() => multiGetResults.GetRequest()); foreach (var doc in multiGetResults.Documents) { if (!doc.Found) { continue; } hits.Add(((IMultiGetHit <T>)doc).ToFindHit().Document); itemsToFind.Remove(doc.Id); } // fallback to doing a find if (itemsToFind.Count > 0 && (HasParent || HasMultipleIndexes)) { var response = await FindAsync(q => q.Id(itemsToFind.Select(id => id.Value)), o => o.PageLimit(1000)).AnyContext(); do { if (response.Hits.Count > 0) { hits.AddRange(response.Hits.Where(h => h.Document != null).Select(h => h.Document)); } } while (await response.NextPageAsync().AnyContext()); } if (IsCacheEnabled && options.ShouldUseCache()) { foreach (var item in hits.OfType <IIdentity>()) { await Cache.SetAsync(item.Id, item, options.GetExpiresIn()).AnyContext(); } } return(hits.AsReadOnly()); }
protected async Task <TResult> GetCachedQueryResultAsync <TResult>(ICommandOptions options, string cachePrefix = null, string cacheSuffix = null) { if (!IsCacheEnabled || options == null || !options.ShouldReadCache() || !options.HasCacheKey()) { return(default);
public virtual async Task <IReadOnlyCollection <T> > GetByIdsAsync(Ids ids, ICommandOptions options = null) { var idList = ids?.Distinct().Where(i => !String.IsNullOrEmpty(i)).ToList(); if (idList == null || idList.Count == 0) { return(EmptyList); } if (!HasIdentity) { throw new NotSupportedException("Model type must implement IIdentity."); } options = ConfigureOptions(options.As <T>()); if (IsCacheEnabled && options.HasCacheKey()) { throw new ArgumentException("Cache key can't be set when calling GetByIds"); } var hits = new List <FindHit <T> >(); if (IsCacheEnabled && options.ShouldReadCache()) { hits.AddRange(await GetCachedFindHit(idList).AnyContext()); } var itemsToFind = idList.Except(hits.Select(i => (Id)i.Id)).ToList(); if (itemsToFind.Count == 0) { return(hits.Where(h => h.Document != null && ShouldReturnDocument(h.Document, options)).Select(h => h.Document).ToList().AsReadOnly()); } var multiGet = new MultiGetDescriptor(); foreach (var id in itemsToFind.Where(i => i.Routing != null || !HasParent)) { multiGet.Get <T>(f => { f.Id(id.Value).Index(ElasticIndex.GetIndex(id)); if (id.Routing != null) { f.Routing(id.Routing); } return(f); }); } var multiGetResults = await _client.MultiGetAsync(multiGet).AnyContext(); _logger.LogRequest(multiGetResults, options.GetQueryLogLevel()); foreach (var doc in multiGetResults.Hits) { hits.Add(((IMultiGetHit <T>)doc).ToFindHit()); itemsToFind.Remove(new Id(doc.Id, doc.Routing)); } // fallback to doing a find if (itemsToFind.Count > 0 && (HasParent || ElasticIndex.HasMultipleIndexes)) { var response = await FindAsync(q => q.Id(itemsToFind.Select(id => id.Value)), o => o.PageLimit(1000)).AnyContext(); do { if (response.Hits.Count > 0) { hits.AddRange(response.Hits.Where(h => h.Document != null)); } } while (await response.NextPageAsync().AnyContext()); } if (IsCacheEnabled && options.ShouldUseCache()) { await AddDocumentsToCacheAsync(hits, options).AnyContext(); } return(hits.Where(h => h.Document != null && ShouldReturnDocument(h.Document, options)).Select(h => h.Document).ToList().AsReadOnly()); }