public static string BuildSelectAttributesClause(EntityMetadata entityMetadata, QueryCacheKey.QueryMode queryMode
                                                         , SearchRequestDto dto = null)
        {
            var buffer = new StringBuilder();

            if (queryMode == QueryCacheKey.QueryMode.Count)
            {
                return(CountClause);
            }

            buffer.AppendFormat("select ");
            if (entityMetadata.FetchLimit() != null && queryMode == QueryCacheKey.QueryMode.Sync)
            {
                buffer.Append(string.Format(" top({0}) ", entityMetadata.FetchLimit()));
            }

            var attributes = entityMetadata.Attributes(NoCollections) as IList <EntityAttribute>
                             ?? entityMetadata.Attributes(NoCollections).ToList();

            var hasProjection = dto != null && dto.ProjectionFields.Count > 0;

            if (hasProjection)
            {
                foreach (ProjectionField field in dto.ProjectionFields)
                {
                    if (field.Name.StartsWith("#"))
                    {
                        if (field.Name.StartsWith("#null"))
                        {
                            //this way we can map null attributes, that can be used for unions
                            //see changeunionschema of hapag´s metadata.xml
                            buffer.AppendFormat("null" + SelectSeparator);
                        }
                        //this is an unmapped attribute
                        continue;
                    }
                    var result = LocateAttribute(entityMetadata, attributes, field);
                    if (!field.Name.Contains('.') && result == null)
                    {
                        //this field is not mapped
                        continue;
                    }
                    string aliasAttribute;
                    if (result != null && result.Item1.Query != null)
                    {
                        aliasAttribute = AliasAttribute(entityMetadata, field.Alias, result.Item1, result.Item2);
                    }
                    else
                    {
                        aliasAttribute = AliasAttribute(entityMetadata, field);
                    }
                    buffer.AppendFormat(aliasAttribute + SelectSeparator);
                }
            }
            else
            {
                for (var i = 0; i < attributes.Count; i++)
                {
                    var entityAttribute = attributes[i];
                    if (entityAttribute.Name.StartsWith("#null"))
                    {
                        //this way we can map null attributes, that can be used for unions
                        //see changeunionschema of hapag´s metadata.xml
                        buffer.AppendFormat("null" + SelectSeparator);
                    }
                    else
                    {
                        var aliasAttribute = AliasAttribute(entityMetadata, entityAttribute);
                        buffer.AppendFormat(aliasAttribute + SelectSeparator);
                    }
                }
            }
            return(buffer.ToString().Substring(0, buffer.Length - SelectSeparator.Count()) + " ");
        }