/// <summary>
 /// Execute the given query as an synchronous operation.
 /// </summary>
 /// <param name="query">The query to be executed</param>
 /// <param name="options">Query options to use for this query</param>
 /// <returns>The result of the given query</returns>
 public TResult QuerySync(TQuery query, EntryOptions options)
 {
     if ((options.Behaviors & EntryBehaviors.LookupCache) == EntryBehaviors.LookupCache)
     {
         if ((options.Behaviors & EntryBehaviors.SaveToCache) == EntryBehaviors.SaveToCache)
         {
             return(m_queryTaskCache.GetOrAdd(query, new Lazy <TResult>(() => DoQuerySync(query)), options).Value);
         }
         else
         {
             Lazy <TResult> lazyResult;
             if (m_queryTaskCache.TryGet(query, out lazyResult))
             {
                 return(lazyResult.Value);
             }
             else
             {
                 return(DoQuerySync(query));
             }
         }
     }
     else
     {
         if ((options.Behaviors & EntryBehaviors.SaveToCache) == EntryBehaviors.SaveToCache)
         {
             var newQueryTask = new Lazy <TResult>(() => DoQuerySync(query));
             m_queryTaskCache.Set(query, newQueryTask, options);
             return(newQueryTask.Value);
         }
         else
         {
             return(DoQuerySync(query));
         }
     }
 }
        /// <summary>
        /// Execute the given query as an asynchronous operation with a specified cache policy.
        /// </summary>
        /// <param name="query">The query to be executed</param>
        /// <param name="options">The cache policy options.</param>
        /// <returns>The task object representing the asynchronous operation</returns>
        public Task <TResult> QueryAsync(TQuery query, EntryOptions options)
        {
            Task <TResult> queryTask = null;

            if ((options.Behaviors & EntryBehaviors.LookupCache) == EntryBehaviors.LookupCache)
            {
                if ((options.Behaviors & EntryBehaviors.SaveToCache) == EntryBehaviors.SaveToCache)
                {
                    queryTask = m_queryTaskCache.GetOrAdd(query, new AsyncLazy <TResult>(() => DoQueryAsync(query)), options).Value;
                }
                else
                {
                    AsyncLazy <TResult> asyncLazyResult;
                    if (m_queryTaskCache.TryGet(query, out asyncLazyResult))
                    {
                        queryTask = asyncLazyResult.Value;
                    }
                    else
                    {
                        //no task cached, do it directly
                        return(DoQueryAsync(query));
                    }
                }

                //re-query if the task is canceld or failed.
                if ((queryTask.IsFaulted || queryTask.IsCanceled) && (options.Behaviors & EntryBehaviors.ReQueryWhenErrorCached) == EntryBehaviors.ReQueryWhenErrorCached)
                {
                    options.Behaviors ^= EntryBehaviors.LookupCache;
                    this.QueryAsync(query, options);
                }

                //query is cached, just await the result
                return(queryTask);
            }
            else
            {
                if ((options.Behaviors & EntryBehaviors.SaveToCache) == EntryBehaviors.SaveToCache)
                {
                    var newQueryTask = new AsyncLazy <TResult>(() => DoQueryAsync(query));
                    m_queryTaskCache.Set(query, newQueryTask, options);
                    return(newQueryTask.Value);
                }
                else
                {
                    return(DoQueryAsync(query));
                }
            }
        }