/// <summary>
        /// Clear out any "compile" state
        /// </summary>
        internal void Unprepare()
        {
            this._commandDefinition   = null;
            this._preparedCommandTree = null;

            // Clear the dirty flag on the parameters and parameter collection
            _parameters.ResetIsDirty();
        }
        /// <summary>
        /// Creates a prepared version of this command without regard to the current connection state.
        /// Called by both <see cref="Prepare"/> and <see cref="ToTraceString"/>.
        /// </summary>
        private void InnerPrepare()
        {
            // Unprepare if the parameters have changed to force a reprepare
            if (_parameters.IsDirty)
            {
                Unprepare();
            }

            _commandDefinition = GetCommandDefinition();
            Debug.Assert(null != _commandDefinition, "_commandDefinition cannot be null");
        }
        /// <summary>
        /// Creates a commandDefinition for the command, using the options specified.
        ///
        /// Note: This method must not be side-effecting of the command
        /// </summary>
        /// <returns>the command definition</returns>
        private EntityCommandDefinition CreateCommandDefinition()
        {
            MakeCommandTree();
            // Always check the CQT metadata against the connection metadata (internally, CQT already
            // validates metadata consistency)
            if (!_preparedCommandTree.MetadataWorkspace.IsMetadataWorkspaceCSCompatible(this.Connection.GetMetadataWorkspace()))
            {
                throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_CommandTreeMetadataIncompatible);
            }
            EntityCommandDefinition result = EntityProviderServices.Instance.CreateCommandDefinition(this._connection.StoreProviderFactory, this._preparedCommandTree);

            return(result);
        }
        /// <summary>
        /// Constructs a EntityParameter from a CQT parameter.
        /// </summary>
        /// <param name="queryParameter"></param>
        /// <returns></returns>
        private static EntityParameter CreateEntityParameterFromQueryParameter(KeyValuePair <string, TypeUsage> queryParameter)
        {
            // We really can't have a parameter here that isn't a scalar type...
            Debug.Assert(TypeSemantics.IsScalarType(queryParameter.Value), "Non-scalar type used as query parameter type");

            EntityParameter result = new EntityParameter();

            result.ParameterName = queryParameter.Key;

            EntityCommandDefinition.PopulateParameterFromTypeUsage(result, queryParameter.Value, isOutParam: false);

            return(result);
        }
        public string ToTraceString()
        {
            CheckConnectionPresent();

            InnerPrepare();

            EntityCommandDefinition commandDefinition = _commandDefinition;

            if (null != commandDefinition)
            {
                return(commandDefinition.ToTraceString());
            }
            return(string.Empty);
        }
        /// <summary>
        /// Gets an entitycommanddefinition from cache if a match is found for the given cache key.
        /// </summary>
        /// <param name="entityCommandDefinition">out param. returns the entitycommanddefinition for a given cache key</param>
        /// <returns>true if a match is found in cache, false otherwise</returns>
        private bool TryGetEntityCommandDefinitionFromQueryCache(out EntityCommandDefinition entityCommandDefinition)
        {
            Debug.Assert(null != _connection, "Connection must not be null at this point");
            entityCommandDefinition = null;

            //
            // if EnableQueryCaching is false, then just return to force the CommandDefinition to be created
            //
            if (!this._enableQueryPlanCaching || string.IsNullOrEmpty(this._esqlCommandText))
            {
                return(false);
            }

            //
            // Create cache key
            //
            EntityClientCacheKey queryCacheKey = new EntityClientCacheKey(this);

            //
            // Try cache lookup
            //
            QueryCacheManager queryCacheManager = _connection.GetMetadataWorkspace().GetQueryCacheManager();

            Debug.Assert(null != queryCacheManager, "QuerycacheManager instance cannot be null");
            if (!queryCacheManager.TryCacheLookup(queryCacheKey, out entityCommandDefinition))
            {
                //
                // if not, construct the command definition using no special options;
                //
                entityCommandDefinition = CreateCommandDefinition();

                //
                // add to the cache
                //
                QueryCacheEntry outQueryCacheEntry = null;
                if (queryCacheManager.TryLookupAndAdd(new QueryCacheEntry(queryCacheKey, entityCommandDefinition), out outQueryCacheEntry))
                {
                    entityCommandDefinition = (EntityCommandDefinition)outQueryCacheEntry.GetTarget();
                }
            }

            Debug.Assert(null != entityCommandDefinition, "out entityCommandDefinition must not be null");

            return(true);
        }
        /// <summary>
        /// Internal constructor used by EntityCommandDefinition
        /// </summary>
        /// <param name="commandDefinition">The prepared command definition that can be executed using this EntityCommand</param>
        internal EntityCommand(EntityCommandDefinition commandDefinition)
            : this()
        {
            // Assign other member fields from the parameters
            this._commandDefinition = commandDefinition;
            this._parameters        = new EntityParameterCollection();

            // Make copies of the parameters
            foreach (EntityParameter parameter in commandDefinition.Parameters)
            {
                this._parameters.Add(parameter.Clone());
            }

            // Reset the dirty flag that was set to true when the parameters were added so that it won't say
            // it's dirty to start with
            this._parameters.ResetIsDirty();

            // Track the fact that this command was created from and represents an already prepared command definition
            this._isCommandDefinitionBased = true;
        }
        /// <summary>
        /// Get the command definition for the command; will construct one if there is not already
        /// one constructed, which means it will prepare the command on the client.
        /// </summary>
        /// <returns>the command definition</returns>
        internal EntityCommandDefinition GetCommandDefinition()
        {
            EntityCommandDefinition entityCommandDefinition = _commandDefinition;

            // Construct the command definition using no special options;
            if (null == entityCommandDefinition)
            {
                //
                // check if the _commandDefinition is in cache
                //
                if (!TryGetEntityCommandDefinitionFromQueryCache(out entityCommandDefinition))
                {
                    //
                    // if not, construct the command definition using no special options;
                    //
                    entityCommandDefinition = CreateCommandDefinition();
                }

                _commandDefinition = entityCommandDefinition;
            }

            return(entityCommandDefinition);
        }
 /// <summary>
 /// Constructs a new EntityCommand given a EntityConnection and an EntityCommandDefition. This
 /// constructor is used by ObjectQueryExecution plan to execute an ObjectQuery.
 /// </summary>
 /// <param name="connection">The connection against which this EntityCommand should execute</param>
 /// <param name="commandDefinition">The prepared command definition that can be executed using this EntityCommand</param>
 internal EntityCommand(EntityConnection connection, EntityCommandDefinition entityCommandDefinition)
     : this(entityCommandDefinition)
 {
     this._connection = connection;
 }