/// <summary> /// Executes a get/query/scan request against the table /// </summary> internal object LoadEntities(TranslationResult translationResult, Type entityType) { // cancelling the previous index creation, if there was one this.CurrentIndexCreator = null; // skipping added and removed entities this.ClearModifications(); // if a HashKey value was explicitly specified if (this.HashKeyValue != null) { // then adding a condition for it translationResult.Conditions.AddCondition ( this.TableDefinition.HashKeys[0], new SearchCondition(ScanOperator.Equal, this.HashKeyValue) ); } #if DEBUG this._loadOperationStopwatch = new Stopwatch(); this._loadOperationStopwatch.Start(); #endif return this.InternalLoadEntities(translationResult, entityType); }
public QueryableMethodsVisitor(Type entityType, Type tableEntityType) { this._tableEntityType = tableEntityType; this.EnumerableParameterExp = Expression.Parameter(typeof(IQueryable<>).MakeGenericType(entityType)); this.TranslationResult = new TranslationResult(tableEntityType.Name); }
private bool TryLoadFromCache(TranslationResult translationResult, Type entityType, out object result) { result = null; var conditions4Cache = translationResult.Conditions; // if an explicit HashKey value is specified for table, then // we need to remove a condition for it from SearchConditions before passing them to cache // implementation. That's because the entity's Type doesn't contain a HashKey property. if (this.HashKeyValue != null) { conditions4Cache = conditions4Cache.ExcludeField(this.TableDefinition.HashKeys[0]); } // implementing Count() if (translationResult.CountRequested) { int? countFromCache = this.Cache.GetCount(conditions4Cache); if (countFromCache.HasValue) { result = countFromCache.Value; return true; } } else { // getting the entities themselves from cache var docsFromCache = this.Cache.GetEntities(conditions4Cache, translationResult.AttributesToGet, translationResult.OrderByColumn, translationResult.OrderByDesc); if (docsFromCache != null) { result = this.CreateDocArrayReader(docsFromCache, entityType, translationResult.ProjectionFunc); return true; } } // If we failed to get from cache, then start filling an index in cache // (this should be started before querying DynamoDb and only when table (full) entities are requested) this.CurrentIndexCreator = (translationResult.ProjectionFunc == null) ? this.Cache.StartCreatingIndex(conditions4Cache) : this.Cache.StartCreatingProjectionIndex(conditions4Cache, translationResult.AttributesToGet) ; return false; }
private bool TryExecuteQuery(TranslationResult translationResult, Type entityType, out object resultingReader) { resultingReader = null; QueryFilter queryFilter; string indexName; // if we failed to compose a query with table's keys and local secondary indexes if (!translationResult.TryGetQueryFilterForTable(this.TableDefinition, out queryFilter, out indexName)) { // then trying to find a suitable Global Secondary Index var matchingIndex = this.TableDefinition .GlobalSecondaryIndexes.Values .FirstOrDefault ( index => translationResult.TryGetQueryFilterForGlobalSeconaryIndex(index, out queryFilter) ); if (matchingIndex == null) { return false; } indexName = matchingIndex.IndexName; } var queryConfig = new QueryOperationConfig { Filter = queryFilter, CollectResults = false, ConsistentRead = this._consistentRead, IndexName = indexName }; // if a projection is specified - then getting only the required list of fields if (translationResult.AttributesToGet != null) { queryConfig.Select = SelectValues.SpecificAttributes; queryConfig.AttributesToGet = translationResult.AttributesToGet; } var searchResult = this.TableDefinition.Query(queryConfig); if (string.IsNullOrEmpty(queryConfig.IndexName)) { this.Log("DynamoDb query: " + translationResult); } else { this.Log("DynamoDb index query: " + translationResult + ". Index name: " + queryConfig.IndexName); } resultingReader = this.CreateReader(searchResult, entityType, translationResult.ProjectionFunc); return true; }
private bool TryExecuteGet(TranslationResult translationResult, Type entityType, out object result) { result = null; var entityKey = translationResult.TryGetEntityKeyForTable(this.TableDefinition); if (entityKey == null) { return false; } Document resultDoc = null; // first trying to get entity from cache, but only if it's not a projection if (ReferenceEquals(this.TableEntityType, entityType)) { resultDoc = this.Cache.GetSingleEntity(entityKey); } if (resultDoc != null) { this.Log("Get from cache: " + translationResult); } else { // if the entity is not found in cache - then getting it from DynamoDb resultDoc = this.TableDefinition.GetItem ( this.EntityKeyGetter.GetKeyDictionary(entityKey), new GetItemOperationConfig { AttributesToGet = translationResult.AttributesToGet, ConsistentRead = this._consistentRead } ); // putting the entity to cache as well this.Cache.PutSingleLoadedEntity(entityKey, resultDoc); this.Log("Get from DynamoDb: " + translationResult); } // creating an enumerator for a single value or an empty enumerator result = this.CreateSingleDocReader(resultDoc, entityType, translationResult.ProjectionFunc); return true; }
private bool TryExecuteBatchGet(TranslationResult translationResult, Type entityType, out object resultingReader) { resultingReader = null; var batchGet = translationResult.GetBatchGetOperationForTable(this.TableDefinition); if (batchGet == null) { return false; } // if a projection is specified - then getting only the required list of fields if (translationResult.AttributesToGet != null) { batchGet.AttributesToGet = translationResult.AttributesToGet; } batchGet.Execute(); this.Log("DynamoDb batch get: " + translationResult); resultingReader = this.CreateDocArrayReader(batchGet.Results, entityType, translationResult.ProjectionFunc); return true; }
private object InternalLoadEntities(TranslationResult translationResult, Type entityType) { // first trying to execute get object result; if (this.TryExecuteGet(translationResult, entityType, out result)) { return result; } // now trying to load a query from cache if (this.TryLoadFromCache(translationResult, entityType, out result)) { return result; } // finally requesting data from DynamoDb if (!this.TryExecuteBatchGet(translationResult, entityType, out result)) { if (!this.TryExecuteQuery(translationResult, entityType, out result)) { result = this.ExecuteScan(translationResult, entityType); } } // Implementing Count(). // Currently Count() causes a full fetch of all matched entities from DynamoDb. // Yes, there's an option to request just the count of them from DynamoDb. // But it will cost you the same money as a full fetch! // So, it might be more efficient to request (and put to cache) all of them right now. // TODO: implement an option for this. if (translationResult.CountRequested) { return ((IEnumerable)result).Count(entityType); } // implementing OrderBy if (!string.IsNullOrEmpty(translationResult.OrderByColumn)) { result = ((IEnumerable)result).OrderBy(entityType, translationResult.OrderByColumn, translationResult.OrderByDesc); } return result; }
private object ExecuteScan(TranslationResult translationResult, Type entityType) { var scanConfig = new ScanOperationConfig { Filter = translationResult.GetScanFilterForTable(this.TableDefinition), CollectResults = false }; if (translationResult.AttributesToGet != null) { scanConfig.Select = SelectValues.SpecificAttributes; scanConfig.AttributesToGet = translationResult.AttributesToGet; } var searchResult = this.TableDefinition.Scan(scanConfig); this.Log("DynamoDb scan: " + translationResult); return this.CreateReader(searchResult, entityType, translationResult.ProjectionFunc); }
/// <summary> /// Returns a single entity by it's keys. Very useful in ASP.Net MVC /// </summary> protected internal object Find(params object[] keyValues) { if (this.KeyNames.Length != keyValues.Length) { throw new InvalidOperationException ( string.Format ( "Table {0} has {1} key fields, but {2} key values was provided", this.TableDefinition.TableName, this.KeyNames.Length, keyValues.Length ) ); } // constructing a GET query var tr = new TranslationResult(this.TableEntityType.Name); for (int i = 0; i < keyValues.Length; i++) { var condition = new SearchCondition ( ScanOperator.Equal, keyValues[i].ToDynamoDbEntry(keyValues[i].GetType()) ); tr.Conditions[this.KeyNames[i]] = new List<SearchCondition> { condition }; } return this.LoadEntities(tr, this.TableEntityType); }