/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			var counter = 0;

			// check for id, guid or pointer
			int id;
			if (parameters.TryGetAndRemove(context, "id", out id))
			{
				query.Add(new IsPropertyEqualSpecification("id", id));
				counter++;
			}
			string guids;
			if (parameters.TryGetAndRemove(context, "guid", out guids) && !string.IsNullOrEmpty(guids))
			{
				// split the value
				var values = guids.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();
				query.Add(new IsPropertyInSpecification("guid", values));
				counter++;
			}
			NodePointer pointer;
			if (parameters.TryGetAndRemove(context, "pointer", out pointer))
			{
				query.Add(new IsPropertyEqualSpecification("id", pointer.Id));
				counter++;
			}

			// check for ambigous parameters
			if (counter > 1)
				throw new InvalidOperationException("Detected an ambigious id parmeters. Remove either id, guid or pointer.");
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// check the input
			int pageNumber;
			var hasPageNumber = parameters.TryGetAndRemove(context, "pageNumber", out pageNumber);
			int pageSize;
			var hasPageSize = parameters.TryGetAndRemove(context, "pageSize", out pageSize);

			// add the paging query component
			if ((hasPageNumber && hasPageSize))
				query.Add(new PagingQueryComponent(pageNumber, pageSize));
		}
		/// <summary>
		/// Gets the dataset.
		/// </summary>
		/// <param name="context">The request context.</param>
		/// <param name="attributes">The attributes of this tag.</param>
		/// <returns>Returns the result.</returns>
		protected override Dataset Get(IMansionContext context, IPropertyBag attributes)
		{
			// get the component and method names
			string componentName;
			if (!attributes.TryGetAndRemove(context, "componentName", out componentName))
				throw new AttributeNullException("componentName", this);
			string methodName;
			if (!attributes.TryGetAndRemove(context, "methodName", out methodName))
				throw new AttributeNullException("methodName", this);

			// invoke the method
			return context.InvokeMethodOnComponent<Dataset>(componentName, methodName, attributes);
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// check for search
			string where;
			if (parameters.TryGetAndRemove(context, "sqlWhere", out where) && !string.IsNullOrEmpty(where))
				query.Add(new SqlWhereSpecification(where));
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// check for the cache flag
			object tmp;
			if (parameters.TryGetAndRemove(context, StorageOnlyQueryComponent.PropertyKey, out tmp))
				query.Add(new StorageOnlyQueryComponent());
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			var clauseCounter = 0;

			// get the depth
			var depthValue = new Lazy<int?>(() =>
			                                {
			                                	int? depth = 1;
			                                	string depthString;
			                                	if (parameters.TryGetAndRemove(context, "depth", out depthString))
			                                	{
			                                		// check for any
			                                		if ("any".Equals(depthString, StringComparison.OrdinalIgnoreCase))
			                                			depth = null;
			                                		else
			                                		{
			                                			// parse the depth
			                                			depth = conversionService.Convert(context, depthString, 1);
			                                		}
			                                	}
			                                	return depth;
			                                });

			// check for parentPointer
			NodePointer parentPointer;
			if (parameters.TryGetAndRemove(context, "childPointer", out parentPointer))
			{
				query.Add(ParentOfSpecification.Child(parentPointer, depthValue.Value));
				clauseCounter++;
			}

			// check for pointer
			Node parentNode;
			if (parameters.TryGetAndRemove(context, "childSource", out parentNode))
			{
				query.Add(ParentOfSpecification.Child(parentNode.Pointer, depthValue.Value));
				clauseCounter++;
			}

			// sort on depth if no explicit sort has been set
			if (clauseCounter > 0 && !parameters.Contains("sort"))
				query.Add(new SortQueryComponent(DefaultSort));

			// check for ambigous parameters
			if (clauseCounter > 1)
				throw new InvalidOperationException("Detected an ambigious parent of clause. Remove either childPointer or childSource.");
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// parse the sorts and add them to the query
			string sortString;
			if (parameters.TryGetAndRemove(context, "sort", out sortString) && !string.IsNullOrEmpty(sortString))
				query.Add(Sort.Parse(sortString));
			else
				query.Add(Sort.DefaultSort);
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			int limit;
			if (!parameters.TryGetAndRemove(context, "limit", out limit))
				return;

			// parse the sorts and add them to the query
			query.Add(new LimitQueryComponent(limit));
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			Specification where;
			if (!parameters.TryGetAndRemove(context, "where", out where))
				return;

			// parse the sorts and add them to the query
			query.Add(where);
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// check for the cache flag
			bool isCachable;
			if (!parameters.TryGetAndRemove(context, "cache", out isCachable))
				isCachable = true;

			// add the query component
			query.Add(new CacheQueryComponent(isCachable));
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// if the authorization is bypassed do not add the security check
			// TODO: add validator logic to make sure the type supports authorization
			bool bypassAuthorization;
			if (parameters.TryGetAndRemove(context, "bypassAuthorization", out bypassAuthorization) && bypassAuthorization)
				query.Add(AllowedRolesSpecification.Any());
			else
				query.Add(AllowedRolesSpecification.UserRoles(context));
		}
		/// <summary>
		/// Gets the row.
		/// </summary>
		/// <param name="context">The request context.</param>
		/// <param name="attributes">The attributes of this tag.</param>
		/// <returns>Returns the result.</returns>
		protected override IPropertyBag Get(IMansionContext context, IPropertyBag attributes)
		{
			// check if query source is specified
			IPropertyBag queryProperties;
			if (attributes.TryGetAndRemove(context, "querySource", out queryProperties))
				attributes = queryProperties.Copy().Merge(attributes);

			// invoke template method
			return Retrieve(context, attributes, context.Repository, parser);
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// loop over all the facet properties
			var facetPropertyNames = parameters.Names.Where(candidate => candidate.StartsWith("facet")).ToList();
			foreach (var facetPropertyName in facetPropertyNames)
			{
				// retrieve the facet from the property
				FacetDefinition facet;
				if (!parameters.TryGetAndRemove(context, facetPropertyName, out facet))
					throw new InvalidOperationException(string.Format("Property {0} did not contain a valid facet", facetPropertyName));

				// add the query component
				query.Add(new FacetQueryComponent(facet));
			}
		}
		/// <summary>
		/// Maps the given <paramref name="dbRecord"/> to <paramref name="properties"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="dbRecord">The <see cref="DbRecord"/> which to map.</param>
		/// <param name="properties">The <see cref="IPropertyBag"/> in which to store the mapped result.</param>
		protected override void DoMap(IMansionContext context, DbRecord dbRecord, IPropertyBag properties)
		{
			// set all the column values as properties
			foreach (var ordinals in dbRecord.GetUnreadOrdinals())
			{
				// if the column is empty remove the value from the properties, otherwise set the value from the column
				if (dbRecord.IsDBNull(ordinals))
				{
					object obj;
					properties.TryGetAndRemove(context, dbRecord.GetName(ordinals), out obj);
				}
				else
					properties.Set(dbRecord.GetName(ordinals), dbRecord.GetValue(ordinals));
			}
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// get the type name is any
			string typeNames;
			if (!parameters.TryGetAndRemove(context, "type", out typeNames) && string.IsNullOrEmpty(typeNames))
				return;

			// parse the type names
			var types = typeNames.Split(',').Select(x => typeService.Load(context, x)).ToArray();
			if (types.Length == 0)
				return;

			// add the type hints to the query
			query.Add(types);
			query.Add(new IsPropertyInSpecification("type", types.Select(type => type.Name)));
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// find autocomplete properties
			foreach (var propertyName in parameters.Names.Where(x => x.EndsWith(Postfix, StringComparison.OrdinalIgnoreCase)).ToArray())
			{
				// remove the parameter
				string value;
				if (!parameters.TryGetAndRemove(context, propertyName, out value))
					continue;

				// cut of the autocomplete postfix
				var propertyNameWithoutPostix = propertyName.Substring(0, propertyName.Length - Postfix.Length);

				// create the specification
				query.Add(new AutocompleteSpecification(propertyNameWithoutPostix, value));
			}
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// loop through all the remaining properties
			foreach (var propertyName in parameters.Names.ToArray())
			{
				// guard against empty properties
				string valueString;
				if (!parameters.TryGetAndRemove(context, propertyName, out valueString) || string.IsNullOrWhiteSpace(valueString))
					continue;

				// parse the parameters, ignoring properties without values
				object[] values = (valueString).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();
				if (values.Length == 0)
					continue;

				// turn it into a specification
				query.Add(SpecificationFactory.IsIn(propertyName, values));
			}
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			// get the type name is any
			string baseTypeNames;
			if (!parameters.TryGetAndRemove(context, "baseType", out baseTypeNames) && string.IsNullOrEmpty(baseTypeNames))
				return;

			// parse the base type names
			var baseTypes = baseTypeNames.Split(',').Select(x => typeService.Load(context, x)).ToArray();
			if (baseTypes.Length == 0)
				return;

			// get all the types
			var types = baseTypes.SelectMany(baseType =>
			                                 {
			                                 	var list = new List<ITypeDefinition>(new[] {baseType});
			                                 	list.AddRange(baseType.GetInheritingTypes(context));
			                                 	return list;
			                                 }).ToArray();

			// add the type hints to the query
			query.Add(types);
			query.Add(new IsPropertyInSpecification("type", types.Select(type => type.Name)));
		}
		/// <summary>
		/// Processes the <paramref name="parameters"/> and turn them into <paramref name="query"/>.
		/// </summary>
		/// <param name="context">The <see cref="IMansionContext"/>.</param>
		/// <param name="parameters">The parameters which to process.</param>
		/// <param name="query">The <see cref="Query"/> in which to set the parameters.</param>
		protected override void DoProcess(IMansionContext context, IPropertyBag parameters, Query query)
		{
			string status;
			if (parameters.TryGetAndRemove(context, "status", out status) && !string.IsNullOrEmpty(status))
				query.Add(StatusSpecification.Is(status));
		}
		/// <summary>
		/// 
		/// </summary>
		/// <param name="context"></param>
		/// <param name="queryBuilder"></param>
		/// <param name="record"> </param>
		/// <param name="modifiedProperties"></param>
		protected override void DoToUpdateStatement(IMansionContext context, ModificationQueryBuilder queryBuilder, Record record, IPropertyBag modifiedProperties)
		{
			// allow update of relational column on special cases, most likely used when fixing the repository integrity
			if (modifiedProperties.Get(context, "_allowRelationPropertiesUpdate", false))
			{
				string name;
				if (modifiedProperties.TryGet(context, "name", out name))
					queryBuilder.AddColumnValue("name", name, DbType.String);
				string type;
				if (modifiedProperties.TryGet(context, "type", out type))
					queryBuilder.AddColumnValue("type", type, DbType.String);
				int depth;
				if (modifiedProperties.TryGet(context, "depth", out depth))
					queryBuilder.AddColumnValue("depth", depth, DbType.Int32);
				int parentId;
				if (modifiedProperties.TryGet(context, "parentId", out parentId))
					queryBuilder.AddColumnValue("parentId", parentId, DbType.Int32);
				string parentPointer;
				if (modifiedProperties.TryGet(context, "parentPointer", out parentPointer))
					queryBuilder.AddColumnValue("parentPointer", parentPointer, DbType.String);
				string parentPath;
				if (modifiedProperties.TryGet(context, "parentPath", out parentPath))
					queryBuilder.AddColumnValue("parentPath", parentPath, DbType.String);
				string parentStructure;
				if (modifiedProperties.TryGet(context, "parentStructure", out parentStructure))
					queryBuilder.AddColumnValue("parentStructure", parentStructure, DbType.String);
				return;
			}

			// make sure the relational intgrety is not comprimised
			if (modifiedProperties.Names.Intersect(ReservedPropertyName, StringComparer.OrdinalIgnoreCase).Any())
				throw new InvalidOperationException("The relational properties can not be changed");

			// get the pointer
			NodePointer pointer;
			if (!record.TryGet(context, "pointer", out pointer))
				throw new InvalidOperationException("Could not update this record because it did not contain a pointer");

			//  add the id an pointer parameters
			var idParameterName = queryBuilder.AddParameter("id", pointer.Id, DbType.Int32);
			var pointerParameterName = queryBuilder.AddParameter("pointer", pointer.PointerString + "-%", DbType.String);

			// check if the name changed
			string newName;
			if (modifiedProperties.TryGetAndRemove(context, "name", out newName))
			{
				newName = newName.Trim();
				if (string.IsNullOrEmpty(newName))
					throw new InvalidOperationException("Can not update column name with empty string");
				if (newName.Contains(NodePointer.PathSeparator))
					throw new InvalidOperationException(string.Format("Name '{0}' contains invalid characters", newName));
				if (!pointer.Name.Equals(newName))
				{
					// add the name column modification
					queryBuilder.AddColumnValue("name", newName, DbType.String);

					// update the paths
					var oldPathLengthParameterName = queryBuilder.AddParameter("oldPathLength", pointer.PathString.Length + 1, DbType.String);
					var newPathParameterName = queryBuilder.AddParameter("newPath", NodePointer.Rename(pointer, newName).PathString + NodePointer.PathSeparator, DbType.String);
					queryBuilder.AppendQuery(string.Format(@" UPDATE [Nodes] SET [parentPath] = {0} + RIGHT( [parentPath], LEN( [parentPath] ) - {1} ) WHERE ( [parentId] = {2} OR [parentPointer] LIKE {3} )", newPathParameterName, oldPathLengthParameterName, idParameterName, pointerParameterName));
				}
			}

			// check if the type changed
			string newType;
			if (modifiedProperties.TryGetAndRemove(context, "type", out newType))
			{
				newType = newType.Trim();
				if (string.IsNullOrEmpty(newType))
					throw new InvalidOperationException("Can not update column type with empty string");
				if (newType.Contains(NodePointer.StructureSeparator))
					throw new InvalidOperationException(string.Format("Type '{0}' contains invalid characters", newType));
				if (!string.IsNullOrEmpty(newType) && !pointer.Type.Equals(newType, StringComparison.OrdinalIgnoreCase))
				{
					// add the name column modification
					queryBuilder.AddColumnValue("type", newType, DbType.String);

					// update the structures
					var newStructureParameterName = queryBuilder.AddParameter("newStructure", NodePointer.ChangeType(pointer, newType).StructureString + NodePointer.StructureSeparator, DbType.String);
					var oldStructureLengthParameterName = queryBuilder.AddParameter("oldStructureLength", pointer.StructureString.Length + 1, DbType.Int32);
					queryBuilder.AppendQuery(string.Format("UPDATE [Nodes] SET [parentStructure] = {0} + RIGHT( [parentStructure], LEN( [parentStructure] ) - {1} ) WHERE ( [parentId] = {2} OR [parentPointer] LIKE {3} )", newStructureParameterName, oldStructureLengthParameterName, idParameterName, pointerParameterName));
				}
			}
		}