internal WebItemGeneralData(string webProjectPath, string pathRelativeToProject, bool includeFileExtensionInClassName, WebProject webProjectConfiguration)
        {
            this.pathRelativeToProject = pathRelativeToProject;

            // Get the URL for this item. "Plain old class" entity setups do not have URLs.
            urlRelativeToProject = pathRelativeToProject.EndsWith(".cs") ? "" : pathRelativeToProject.Replace(System.IO.Path.DirectorySeparatorChar, '/');

            // Load this item's code if it exists.
            path = StandardLibraryMethods.CombinePaths(webProjectPath, pathRelativeToProject);
            var codePath = path.EndsWith(".cs") ? path : path + ".cs";

            code = File.Exists(codePath) ? File.ReadAllText(codePath) : "";

            // Attempt to get the namespace from the code. If this fails, use a namespace based on the item's path in the project.
            foreach (Match match in Regex.Matches(code, @"namespace\s(?<namespace>.*)\s{"))
            {
                itemNamespace = match.Groups["namespace"].Value;
            }
            if (itemNamespace == null)
            {
                itemNamespace = getNamespaceFromFilePath(webProjectConfiguration.NamespaceAndAssemblyName, pathRelativeToProject);
            }

            className =
                StandardLibraryMethods.GetCSharpIdentifier(
                    System.IO.Path.GetFileNameWithoutExtension(path) + (includeFileExtensionInClassName ? System.IO.Path.GetExtension(path).CapitalizeString() : ""));
            this.webProjectConfiguration = webProjectConfiguration;
        }
		internal static void Generate(
			DBConnection cn, TextWriter writer, string baseNamespace, Database database,
			RedStapler.StandardLibrary.Configuration.SystemDevelopment.Database configuration ) {
			if( configuration.rowConstantTables == null )
				return;

			writer.WriteLine( "namespace " + baseNamespace + "." + database.SecondaryDatabaseName + "RowConstants {" );
			foreach( var table in configuration.rowConstantTables ) {
				Column valueColumn;
				var orderIsSpecified = !table.orderByColumn.IsNullOrWhiteSpace();
				var values = new List<string>();
				var names = new List<string>();
				try {
					var columns = new TableColumns( cn, table.tableName, false );
					valueColumn = columns.AllColumnsExceptRowVersion.Single( column => column.Name.ToLower() == table.valueColumn.ToLower() );
					var nameColumn = columns.AllColumnsExceptRowVersion.Single( column => column.Name.ToLower() == table.nameColumn.ToLower() );

					var cmd = new InlineSelect(
						new[] { valueColumn.Name, nameColumn.Name },
						"FROM " + table.tableName,
						false,
						orderByClause: orderIsSpecified ? "ORDER BY " + table.orderByColumn : "" );
					cmd.Execute(
						cn,
						reader => {
							while( reader.Read() ) {
								if( reader.IsDBNull( reader.GetOrdinal( valueColumn.Name ) ) )
									values.Add( valueColumn.NullValueExpression.Any() ? valueColumn.NullValueExpression : "null" );
								else {
									var valueString = valueColumn.ConvertIncomingValue( reader[ valueColumn.Name ] ).ToString();
									values.Add( valueColumn.DataTypeName == typeof( string ).ToString() ? "\"{0}\"".FormatWith( valueString ) : valueString );
								}
								names.Add( nameColumn.ConvertIncomingValue( reader[ nameColumn.Name ] ).ToString() );
							}
						} );
				}
				catch( Exception e ) {
					throw new UserCorrectableException(
						"Column or data retrieval failed for the " + table.tableName + " row constant table. Make sure the table and the value, name, and order by columns exist.",
						e );
				}

				CodeGenerationStatics.AddSummaryDocComment( writer, "Provides constants copied from the " + table.tableName + " table." );
				var className = table.tableName.TableNameToPascal( cn ) + "Rows";
				writer.WriteLine( "public class " + className + " {" );

				// constants
				for( var i = 0; i < values.Count; i++ ) {
					CodeGenerationStatics.AddSummaryDocComment( writer, "Constant generated from row in database table." );
					// It's important that row constants actually *be* constants (instead of static readonly) so they can be used in switch statements.
					writer.WriteLine( "public const " + valueColumn.DataTypeName + " " + StandardLibraryMethods.GetCSharpIdentifier( names[ i ] ) + " = " + values[ i ] + ";" );
				}

				// one to one map
				var dictionaryType = "OneToOneMap<" + valueColumn.DataTypeName + ", string>";
				writer.WriteLine( "private static readonly " + dictionaryType + " " + dictionaryName + " = new " + dictionaryType + "();" );

				writeStaticConstructor( writer, className, names, values, valueColumn.DataTypeName );

				// methods
				writeGetNameFromValueMethod( writer, valueColumn.DataTypeName );
				writeGetValueFromNameMethod( writer, valueColumn.DataTypeName );
				if( orderIsSpecified ) {
					writeGetValuesToNamesMethod( writer, valueColumn.DataTypeName );
					writeFillListControlMethod( writer, valueColumn );
				}

				writer.WriteLine( "}" ); // class
			}
			writer.WriteLine( "}" ); // namespace
		}