/// <summary>
        /// Creates a new Insert Query object which is ready to use.
        /// </summary>
        /// <param name="fields">Array of EntityFieldCore objects to use to build the insert query</param>
        /// <param name="fieldsPersistenceInfo">Array of IFieldPersistenceInfo objects to use to build the insert query</param>
        /// <param name="query">The query object to fill.</param>
        /// <param name="fieldToParameter">Hashtable which will contain after the call for each field the parameter which contains or will contain the field's value.</param>
        /// <remarks>Generic version.</remarks>
        /// <exception cref="System.ArgumentNullException">When fields is null or fieldsPersistenceInfo is null</exception>
        /// <exception cref="System.ArgumentException">When fields contains no EntityFieldCore instances or fieldsPersistenceInfo is empty.</exception>
        /// <exception cref="ORMQueryConstructionException">When there are no fields to insert in the fields list. This exception is to prevent
        /// INSERT INTO table () VALUES () style queries.</exception>
        protected override void CreateSingleTargetInsertDQ(IEntityFieldCore[] fields, IFieldPersistenceInfo[] fieldsPersistenceInfo,
                                                           IActionQuery query, Dictionary <IEntityFieldCore, DbParameter> fieldToParameter)
        {
            TraceHelper.WriteLineIf(Switch.TraceInfo, "CreateSingleTargetInsertDQ", "Method Enter");
            QueryFragments fragments = new QueryFragments();

            fragments.AddFormatted("INSERT INTO {0}", this.Creator.CreateObjectName(fieldsPersistenceInfo[0]));
            DelimitedStringList fieldNames = fragments.AddCommaFragmentList(true);

            fragments.AddFragment("VALUES");
            DelimitedStringList valueFragments = fragments.AddCommaFragmentList(true);

            DbParameter newParameter;
            bool        hasIdentity = false;

            for (int i = 0; i < fields.Length; i++)
            {
                IEntityFieldCore      field           = fields[i];
                IFieldPersistenceInfo persistenceInfo = fieldsPersistenceInfo[i];

                if (string.IsNullOrEmpty(persistenceInfo.IdentityValueSequenceName))
                {
                    if (!CheckIfFieldNeedsInsertAction(field))
                    {
                        continue;
                    }
                    fieldNames.Add(this.Creator.CreateFieldNameSimple(persistenceInfo, field.Name));
                    AppendFieldToValueFragmentsForInsert(query, fieldToParameter, valueFragments, field, persistenceInfo);
                }
                else
                {
                    newParameter = this.Creator.CreateParameter(field, persistenceInfo, ParameterDirection.InputOutput);
                    query.AddParameterFieldRelation(field, newParameter, persistenceInfo.TypeConverterToUse, parameterValueCanBeNull: false);
                    query.AddSequenceRetrievalQuery(CreateCommand("SELECT @@IDENTITY", query.Connection), false).AddSequenceParameter(newParameter);
                    hasIdentity = true;
                    fieldToParameter.Add(field, newParameter);
                }
            }
            if (fieldNames.Count <= 0)
            {
                if (hasIdentity)
                {
                    // a table with just 1 identity field, use a special case query: INSERT INTO table values ()
                    fieldNames.Clear();
                    valueFragments.Clear();
                    fragments.AddFragment("()");
                }
                else
                {
                    throw new ORMQueryConstructionException("The insert query doesn't contain any fields.");
                }
            }
            query.SetCommandText(MakeParametersAnonymous(fragments.ToString(), query.Parameters));

            TraceHelper.WriteIf(Switch.TraceVerbose, query, "Generated Sql query");
            TraceHelper.WriteLineIf(Switch.TraceInfo, "CreateSingleTargetInsertDQ", "Method Exit");
        }
        /// <summary>
        /// Creates a new Select Query which is ready to use, based on the specified select list and the specified set of relations.
        /// If selectFilter is set to null, all rows are selected.
        /// </summary>
        /// <param name="selectList">list of IEntityFieldCore objects to select</param>
        /// <param name="fieldsPersistenceInfo">Array of IFieldPersistenceInfo objects to use to build the select query</param>
        /// <param name="query">The query to fill.</param>
        /// <param name="selectFilter">A complete IPredicate implementing object which contains the filter for the rows to select. When set to null, no
        /// filtering is done, and all rows are returned.</param>
        /// <param name="maxNumberOfItemsToReturn">The maximum number of items to return with this retrieval query.
        /// If the used Dynamic Query Engine supports it, 'TOP' is used to limit the amount of rows to return.
        /// When set to 0, no limitations are specified.</param>
        /// <param name="sortClauses">The order by specifications for the sorting of the resultset. When not specified, no sorting is applied.</param>
        /// <param name="relationsToWalk">list of EntityRelation objects, which will be used to formulate a FROM clause with INNER JOINs.</param>
        /// <param name="allowDuplicates">Flag which forces the inclusion of DISTINCT if set to true. If the resultset contains fields of type ntext, text or image, no duplicate filtering
        /// is done.</param>
        /// <param name="groupByClause">The list of fields to group by on. When not specified or an empty collection is specified, no group by clause
        /// is added to the query. A check is performed for each field in the selectList. If a field in the selectList is not present in the groupByClause
        /// collection, an exception is thrown.</param>
        /// <param name="relationsSpecified">flag to signal if relations are specified, this is a result of a check. This routine should
        /// simply assume the value of this flag is correct.</param>
        /// <param name="sortClausesSpecified">flag to signal if sortClauses are specified, this is a result of a check. This routine should
        /// simply assume the value of this flag is correct.</param>
        /// <exception cref="System.ArgumentNullException">When selectList is null or fieldsPersistenceInfo is null</exception>
        /// <exception cref="System.ArgumentException">When selectList contains no EntityFieldCore instances or fieldsPersistenceInfo is empty.</exception>
        protected override void CreateSelectDQ(IEntityFieldCore[] selectList, IFieldPersistenceInfo[] fieldsPersistenceInfo,
                                               IRetrievalQuery query, IPredicate selectFilter, long maxNumberOfItemsToReturn, ISortExpression sortClauses,
                                               IRelationCollection relationsToWalk, bool allowDuplicates, IGroupByCollection groupByClause,
                                               bool relationsSpecified, bool sortClausesSpecified)
        {
            TraceHelper.WriteLineIf(Switch.TraceInfo, "CreateSelectDQ", "Method Enter");

            QueryFragments fragments = new QueryFragments();

            fragments.AddFragment("SELECT");
            StringPlaceHolder   distinctPlaceholder = fragments.AddPlaceHolder();
            StringPlaceHolder   topPlaceholder      = fragments.AddPlaceHolder();
            DelimitedStringList projection          = fragments.AddCommaFragmentList(false);

            UniqueList <string> fieldNamesInSelectList;
            bool distinctViolatingTypesFound;
            bool pkFieldSeen;

            AppendResultsetFields(selectList, fieldsPersistenceInfo, relationsToWalk, projection, sortClausesSpecified, allowDuplicates, true, new UniqueList <string>(),
                                  query, out fieldNamesInSelectList, out distinctViolatingTypesFound, out pkFieldSeen);

            bool resultsCouldContainDuplicates = this.DetermineIfDuplicatesWillOccur(relationsToWalk);
            bool distinctEmitted = this.HandleDistinctEmit(sortClauses, allowDuplicates, sortClausesSpecified, query, distinctPlaceholder, distinctViolatingTypesFound,
                                                           (pkFieldSeen && !resultsCouldContainDuplicates), fieldNamesInSelectList);

            bool groupByClauseSpecified = ((groupByClause != null) && (groupByClause.Count > 0));

            if (maxNumberOfItemsToReturn > 0)
            {
                // row limits are emitted always, unless duplicates are required but DISTINCT wasn't emitable. If not emitable, switch to client-side row limitation
                if (distinctEmitted || !resultsCouldContainDuplicates || groupByClauseSpecified || allowDuplicates)
                {
                    topPlaceholder.SetFormatted("TOP {0}", maxNumberOfItemsToReturn);
                }
                else
                {
                    query.RequiresClientSideLimitation = true;
                    query.ManualRowsToTake             = (int)maxNumberOfItemsToReturn;
                }
            }
            if (relationsSpecified)
            {
                fragments.AddFormatted("FROM {0}", relationsToWalk.ToQueryText());
                query.AddParameters(((RelationCollection)relationsToWalk).CustomFilterParameters);
            }
            else
            {
                var persistenceInfoToUse = fieldsPersistenceInfo.FirstOrDefault(p => p != null);
                if ((persistenceInfoToUse != null) && (persistenceInfoToUse.SourceObjectName.Length > 0))
                {
                    fragments.AddFormatted(" FROM {0}", this.Creator.CreateObjectName(persistenceInfoToUse));
                    string targetAlias = this.DetermineTargetAlias(selectList[0], relationsToWalk);
                    if (targetAlias.Length > 0)
                    {
                        fragments.AddFormatted(" {0}", this.Creator.CreateValidAlias(targetAlias));
                    }
                }
            }
            AppendWhereClause(selectFilter, fragments, query);
            AppendGroupByClause(groupByClause, fragments, query);
            AppendOrderByClause(sortClauses, fragments, query);
            query.SetCommandText(MakeParametersAnonymous(fragments.ToString(), query.Parameters));

            TraceHelper.WriteIf(Switch.TraceVerbose, query, "Generated Sql query");
            TraceHelper.WriteLineIf(Switch.TraceInfo, "CreateSelectDQ", "Method Exit");
        }