/// <summary>
		/// Render the where condition for a (batch) load by identifier / collection key
		/// </summary>
		protected SqlStringBuilder WhereString(string alias, string[] columnNames, int batchSize)
		{
			if (columnNames.Length == 1)
			{
				// if not a composite key, use "foo in (?, ?, ?)" for batching
				// if no batch, and not a composite key, use "foo = ?"
				string tableAlias = GenerateAliasForColumn(alias, columnNames[0]);
				InFragment inf = new InFragment().SetColumn(tableAlias, columnNames[0]);

				for (int i = 0; i < batchSize; i++)
					inf.AddValue(Parameter.Placeholder);

				return new SqlStringBuilder(inf.ToFragmentString());
			}
			else
			{
				var fragments = new ConditionalFragment[batchSize];
				for (int i = 0; i < batchSize; i++)
				{
					fragments[i] = new ConditionalFragment()
						.SetTableAlias(alias)
						.SetCondition(columnNames, Parameter.GenerateParameters(columnNames.Length));
				}

				var whereString = new SqlStringBuilder();

				if (fragments.Length == 1)
				{
					// if no batch, use "foo = ? and bar = ?"
					whereString.Add(fragments[0].ToSqlStringFragment());
				}
				else
				{
					// if batching, use "( (foo = ? and bar = ?) or (foo = ? and bar = ?) )"
					var df = new DisjunctionFragment(fragments);

					whereString.Add(StringHelper.OpenParen);
					whereString.Add(df.ToFragmentString());
					whereString.Add(StringHelper.ClosedParen);
				}

				return whereString;
			}
		}
		private string DiscriminatorFilterFragment(string alias)
		{
			const string abstractClassWithNoSubclassExceptionMessageTemplate = 
@"The class {0} can't be instatiated and does not have mapped subclasses; 
possible solutions:
- don't map the abstract class
- map the its subclasses.";

			if (NeedsDiscriminator)
			{
				InFragment frag = new InFragment();

				if (IsDiscriminatorFormula)
				{
					frag.SetFormula(alias, DiscriminatorFormulaTemplate);
				}
				else
				{
					frag.SetColumn(alias, DiscriminatorColumnName);
				}

				string[] subclasses = SubclassClosure;
				int validValuesForInFragment = 0;
				foreach (string t in subclasses)
				{
					var queryable = (IQueryable) Factory.GetEntityPersister(t);
					if (!queryable.IsAbstract)
					{
						frag.AddValue(queryable.DiscriminatorSQLValue);
						validValuesForInFragment++;
					}
				}
				if(validValuesForInFragment == 0)
				{
					throw new NotSupportedException(string.Format(abstractClassWithNoSubclassExceptionMessageTemplate, subclasses[0]));
				}
				StringBuilder buf = new StringBuilder(50).Append(" and ").Append(frag.ToFragmentString().ToString());

				return buf.ToString();
			}
			else
			{
				return string.Empty;
			}
		}
		/// <summary>
		/// Render the where condition for a (batch) load by identifier / collection key
		/// </summary>
		protected SqlStringBuilder WhereString(string alias, string[] columnNames, int batchSize)
		{
			if (columnNames.Length == 1)
			{
				// if not a composite key, use "foo in (?, ?, ?)" for batching
				// if no batch, and not a composite key, use "foo = ?"
				InFragment inf = new InFragment().SetColumn(alias, columnNames[0]);

				for (int i = 0; i < batchSize; i++)
					inf.AddValue(Parameter.Placeholder);

				return new SqlStringBuilder(inf.ToFragmentString());
			}
			else
			{
				Parameter[] columnParameters = Parameter.GenerateParameters(columnNames.Length);
				ConditionalFragment byId = new ConditionalFragment()
					.SetTableAlias(alias)
					.SetCondition(columnNames, columnParameters);

				SqlStringBuilder whereString = new SqlStringBuilder();

				if (batchSize == 1)
				{
					// if no batch, use "foo = ? and bar = ?"
					whereString.Add(byId.ToSqlStringFragment());
				}
				else
				{
					// if a composite key, use "( (foo = ? and bar = ?) or (foo = ? and bar = ?) )" for batching
					whereString.Add(StringHelper.OpenParen); // TODO: unnecessary for databases with ANSI-style joins
					DisjunctionFragment df = new DisjunctionFragment();
					for (int i = 0; i < batchSize; i++)
					{
						df.AddCondition(byId);
					}
					whereString.Add(df.ToFragmentString());
					whereString.Add(StringHelper.ClosedParen); // TODO: unnecessary for databases with ANSI-style joins
				}

				return whereString;
			}
		}
		private string DiscriminatorFilterFragment(string alias)
		{
			if (NeedsDiscriminator)
			{
				InFragment frag = new InFragment();

				if (IsDiscriminatorFormula)
				{
					frag.SetFormula(alias, DiscriminatorFormulaTemplate);
				}
				else
				{
					frag.SetColumn(alias, DiscriminatorColumnName);
				}

				string[] subclasses = SubclassClosure;
				for (int i = 0; i < subclasses.Length; i++)
				{
					IQueryable queryable = (IQueryable)Factory.GetEntityPersister(subclasses[i]);
					if (!queryable.IsAbstract)
						frag.AddValue(queryable.DiscriminatorSQLValue);
				}

				StringBuilder buf = new StringBuilder(50).Append(" and ").Append(frag.ToFragmentString().ToString());

				return buf.ToString();
			}
			else
			{
				return string.Empty;
			}
		}
		private SqlString DiscriminatorWhereCondition(string alias)
		{
			InFragment frag = new InFragment()
				.SetColumn(alias, DiscriminatorColumnName);

			if (IsDiscriminatorFormula)
			{
				frag.SetFormula(alias, DiscriminatorFormulaTemplate);
			}
			else
			{
				frag.SetColumn(alias, DiscriminatorColumnName);
			}

			System.Type[] subclasses = SubclassClosure;
			for (int i = 0; i < subclasses.Length; i++)
			{
				IQueryable queryable = (IQueryable) Factory.GetEntityPersister(subclasses[i]);
				frag.AddValue(queryable.DiscriminatorSQLValue);
			}

			return frag.ToFragmentString();
		}