private static void writeFormItemGetterWithoutValueParams( TextWriter writer, string controlType, ModificationField field, string controlTypeForName, bool includeValidationParams, IEnumerable <CSharpParameter> requiredControlParams, IEnumerable <CSharpParameter> requiredValidationParams, IEnumerable <CSharpParameter> optionalControlParams, IEnumerable <CSharpParameter> optionalValidationParams, IEnumerable <string> additionalSummarySentences) { // NOTE: The "out" parameter logic is a hack. We need to improve CSharpParameter. var body = "return " + StandardLibraryMethods.GetCSharpIdentifierSimple("Get" + field.PascalCasedName + controlTypeForName + "FormItem") + "( false, " + requiredControlParams.Concat(requiredValidationParams) .Select(i => (i.MethodSignatureDeclaration.StartsWith("out ") ? "out " : "") + i.Name) .GetCommaDelimitedStringFromCollection() .AppendDelimiter(", ") + "labelAndSubject: labelAndSubject, labelOverride: labelOverride, " + optionalControlParams.Select(i => i.Name + ": " + i.Name).GetCommaDelimitedStringFromCollection().AppendDelimiter(", ") + "cellSpan: cellSpan, textAlignment: textAlignment" + (includeValidationParams ? ", validationPredicate: validationPredicate" : "") + optionalValidationParams.Select(i => i.Name + ": " + i.Name).GetCommaDelimitedStringFromCollection().PrependDelimiter(", ") + (includeValidationParams ? ", validationErrorNotifier: validationErrorNotifier, additionalValidationMethod: additionalValidationMethod, validationList: validationList" : "") + " );"; writeFormItemGetter( writer, controlType, field, controlTypeForName, "", requiredControlParams, requiredValidationParams, "", optionalControlParams, includeValidationParams, optionalValidationParams, body, additionalSummarySentences); }
private static void writeCreateForSingleRowUpdateMethod( DBConnection cn, string tableName, bool isRevisionHistoryTable, bool isRevisionHistoryClass, string methodNameSuffix) { // header CodeGenerationStatics.AddSummaryDocComment( writer, "Creates a modification object in single-row update mode with the specified current data. All column values in this object will have HasChanged = false, despite being initialized. This object can then be used to do a piecemeal update of the " + tableName + " table." ); writer.Write( "public static " + GetClassName( cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass ) + " CreateForSingleRowUpdate" + methodNameSuffix + "( " ); writeColumnParameterDeclarations( columns.AllColumnsExceptRowVersion ); writer.WriteLine( " ) {" ); // body writer.WriteLine( "var mod = new " + GetClassName( cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass ) + " { modType = ModificationType.Update };" ); // Use the values of key columns as conditions. writer.WriteLine( "mod.conditions = new List<" + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + ">();" ); foreach( var column in columns.KeyColumns ) { writer.WriteLine( "mod.conditions.Add( new " + DataAccessStatics.GetEqualityConditionClassName( cn, database, tableName, column ) + "( " + "@" + StandardLibraryMethods.GetCSharpIdentifierSimple( column.CamelCasedName ) + " ) );" ); } writeColumnValueAssignmentsFromParameters( columns.AllColumnsExceptRowVersion, "mod" ); writer.WriteLine( "mod.markColumnValuesUnchanged();" ); writer.WriteLine( "return mod;" ); writer.WriteLine( "}" ); }
private static void writeFieldsAndPropertiesForColumn( Column column ) { var columnIsReadOnly = !columns.DataColumns.Contains( column ); writer.WriteLine( "private readonly DataValue<" + column.DataTypeName + "> " + getColumnFieldName( column ) + " = new DataValue<" + column.DataTypeName + ">();" ); CodeGenerationStatics.AddSummaryDocComment( writer, "Gets " + ( columnIsReadOnly ? "" : "or sets " ) + "the value for the " + column.Name + " column. Throws an exception if the value has not been initialized. " + getComment( column ) ); var propertyDeclarationBeginning = "public " + column.DataTypeName + " " + StandardLibraryMethods.GetCSharpIdentifierSimple( column.PascalCasedNameExceptForOracle ) + " { get { return " + getColumnFieldName( column ) + ".Value; } "; if( columnIsReadOnly ) writer.WriteLine( propertyDeclarationBeginning + "}" ); else { writer.WriteLine( propertyDeclarationBeginning + "set { " + getColumnFieldName( column ) + ".Value = value; } }" ); CodeGenerationStatics.AddSummaryDocComment( writer, "Indicates whether or not the value for the " + column.Name + " has been set since object creation or the last call to Execute, whichever was latest." ); writer.WriteLine( "public bool " + StandardLibraryMethods.GetCSharpIdentifierSimple( column.PascalCasedNameExceptForOracle ) + "HasChanged { get { return " + getColumnFieldName( column ) + ".Changed; } }" ); } }
private static void writeColumnParameterDeclarations( IEnumerable<Column> columns ) { writer.Write( StringTools.ConcatenateWithDelimiter( ", ", columns.Select( i => i.DataTypeName + " @" + StandardLibraryMethods.GetCSharpIdentifierSimple( i.CamelCasedName ) ).ToArray() ) ); }
private static void writeToIdDictionaryMethod(TextWriter writer, TableColumns tableColumns) { writer.WriteLine("public static Dictionary<" + tableColumns.KeyColumns.Single().DataTypeName + ", Row> ToIdDictionary( this IEnumerable<Row> rows ) {"); writer.WriteLine( "return rows.ToDictionary( i => i." + StandardLibraryMethods.GetCSharpIdentifierSimple(tableColumns.KeyColumns.Single().PascalCasedNameExceptForOracle) + " );"); writer.WriteLine("}"); }
private static void writeColumnProperty(TextWriter writer, Column column) { CodeGenerationStatics.AddSummaryDocComment( writer, "This object will " + (column.AllowsNull && !column.NullValueExpression.Any() ? "sometimes" : "never") + " be null."); writer.WriteLine( "public " + column.DataTypeName + " " + StandardLibraryMethods.GetCSharpIdentifierSimple(column.PascalCasedNameExceptForOracle) + " { get { return __basicRow." + StandardLibraryMethods.GetCSharpIdentifierSimple(column.PascalCasedName) + "; } }"); }
private static void writeAddColumnModificationsMethod( IEnumerable<Column> nonIdentityColumns ) { writer.WriteLine( "private void addColumnModifications( InlineDbModificationCommand cmd ) {" ); foreach( var column in nonIdentityColumns ) { writer.WriteLine( "if( " + getColumnFieldName( column ) + ".Changed )" ); var columnValueExpression = column.GetCommandColumnValueExpression( StandardLibraryMethods.GetCSharpIdentifierSimple( column.PascalCasedNameExceptForOracle ) ); writer.WriteLine( "cmd.AddColumnModification( " + columnValueExpression + " );" ); } writer.WriteLine( "}" ); }
private static void writeGenericGetterWithValueParams(TextWriter writer, ModificationField field, bool?includeValidationMethodReturnValue) { var control = "useValueParameter ? controlGetter( value, labelAndSubject ) : controlGetter( " + StandardLibraryMethods.GetCSharpIdentifierSimple(field.PropertyName) + ", labelAndSubject )"; var body = "return FormItem.Create( labelOverride ?? labelAndSubject, " + control + ", cellSpan: cellSpan, textAlignment: textAlignment" + (includeValidationMethodReturnValue.HasValue ? ", validationGetter: " + getValidationGetter(field, includeValidationMethodReturnValue.Value) : "") + " );"; writeGenericGetter(writer, field, true, includeValidationMethodReturnValue, body); }
private static void writeGenericGetterWithoutValueParams(TextWriter writer, ModificationField field, bool?includeValidationMethodReturnValue) { var controlGetter = "( v, ls ) => controlGetter( v" + (field.TypeName != field.NullableTypeName ? ".Value" : "") + ", ls )"; var body = "return " + StandardLibraryMethods.GetCSharpIdentifierSimple("Get" + field.PascalCasedName + "FormItem") + "( false, " + controlGetter + (includeValidationMethodReturnValue.HasValue ? ", validationMethod" : "") + ", labelAndSubject: labelAndSubject, labelOverride: labelOverride, cellSpan: cellSpan, textAlignment: textAlignment" + (includeValidationMethodReturnValue.HasValue ? ", validationPredicate: validationPredicate, validationErrorNotifier: validationErrorNotifier, additionalValidationMethod: additionalValidationMethod, validationList: validationList" : "") + " );"; writeGenericGetter(writer, field, false, includeValidationMethodReturnValue, body); }
internal static void Generate(string rootPath, string nameSpace, TextWriter writer) { var cssClasses = new HashSet <string>(); foreach (var fileInfo in new DirectoryInfo(rootPath).GetFiles("*.css", SearchOption.AllDirectories)) { new FileReader(fileInfo.FullName).ExecuteInStreamReader( delegate(StreamReader reader) { // Remove comments and styles. // NOTE: We need to find a way to also throw out media query expressions. var text = reader.ReadToEnd().RemoveTextBetweenStrings("/*", "*/").RemoveTextBetweenStrings("{", "}"); foreach (Match match in Regex.Matches(text, @"\.(\w+)")) { cssClasses.Add(match.Groups[1].Value); } }); } if (cssClasses.Any()) { writer.WriteLine("namespace " + nameSpace + " {"); CodeGenerationStatics.AddSummaryDocComment(writer, "This class provides typesafe access to css classes present in *.css files."); writer.WriteLine("public class CssClasses {"); var identifiers = new HashSet <string>(); foreach (var cssClass in cssClasses) { writer.WriteLine("/// <summary>"); writer.WriteLine("/// Constant for the '{0}' class.".FormatWith(cssClass)); writer.WriteLine("/// </summary>"); var identifier = StandardLibraryMethods.GetCSharpIdentifierSimple(cssClass).CapitalizeString(); if (identifiers.Contains(identifier)) { var uniqueIdentifier = identifier; var i = 0; while (identifiers.Contains(uniqueIdentifier)) { uniqueIdentifier = identifier + i++; } identifier = uniqueIdentifier; } identifiers.Add(identifier); writer.WriteLine("public const string " + identifier + " = \"" + cssClass + "\";"); } writer.WriteLine("}"); // class writer.WriteLine("}"); // namespace } }
private static string getValidationGetter(ModificationField field, bool includeValidationMethodReturnValue) { var fieldPropertyName = StandardLibraryMethods.GetCSharpIdentifierSimple(field.PropertyName); var statements = new[] { "if( validationPredicate != null && !validationPredicate() ) return;", (includeValidationMethodReturnValue ? fieldPropertyName + " = " : "") + "validationMethod( control, postBackValues, labelAndSubject, validator );", "if( validator.ErrorsOccurred && validationErrorNotifier != null ) validationErrorNotifier();", "if( !validator.ErrorsOccurred && additionalValidationMethod != null ) additionalValidationMethod( labelAndSubject, validator );" }; return("control => new Validation( ( postBackValues, validator ) => { " + StringTools.ConcatenateWithDelimiter(" ", statements) + " }, validationList ?? EwfPage.Instance.DataUpdate )"); }
private static void writeFormItemGetter( TextWriter writer, string controlType, ModificationField field, string controlTypeForName, string valueParamTypeName, IEnumerable <CSharpParameter> requiredControlParams, IEnumerable <CSharpParameter> requiredValidationParams, string valueParamDefaultValue, IEnumerable <CSharpParameter> optionalControlParams, bool includeValidationParams, IEnumerable <CSharpParameter> optionalValidationParams, string body, IEnumerable <string> additionalSummarySentences) { CodeGenerationStatics.AddSummaryDocComment(writer, getFormItemGetterSummary(field, controlTypeForName, additionalSummarySentences)); CodeGenerationStatics.AddParamDocComment(writer, "additionalValidationMethod", "Passes the labelAndSubject and a validator to the function."); CodeGenerationStatics.AddParamDocComment(writer, "validationList", validationListParamDocComment); var parameters = new List <CSharpParameter>(); if (valueParamTypeName.Length > 0) { parameters.Add(new CSharpParameter("bool", "useValueParameter")); } parameters.AddRange(requiredControlParams); parameters.AddRange(requiredValidationParams); parameters.Add(new CSharpParameter("string", "labelAndSubject", "\"" + getDefaultLabelAndSubject(field) + "\"")); parameters.Add(new CSharpParameter("FormItemLabel", "labelOverride", "null")); if (valueParamTypeName.Length > 0) { parameters.Add(new CSharpParameter(valueParamTypeName, "value", valueParamDefaultValue)); } parameters.AddRange(optionalControlParams); parameters.Add(new CSharpParameter("int?", "cellSpan", "null")); parameters.Add(new CSharpParameter("TextAlignment", "textAlignment", "TextAlignment.NotSpecified")); if (includeValidationParams) { parameters.Add(new CSharpParameter("System.Func<bool>", "validationPredicate", "null")); } parameters.AddRange(optionalValidationParams); if (includeValidationParams) { parameters.Add(new CSharpParameter("System.Action", "validationErrorNotifier", "null")); parameters.Add(new CSharpParameter("System.Action<string,Validator>", "additionalValidationMethod", "null")); parameters.Add(new CSharpParameter("ValidationList", "validationList", "null")); } writer.WriteLine( "public FormItem<" + controlType + "> " + StandardLibraryMethods.GetCSharpIdentifierSimple("Get" + field.PascalCasedName + controlTypeForName + "FormItem") + "( " + parameters.Select(i => i.MethodSignatureDeclaration).GetCommaDelimitedStringFromCollection() + " ) {"); writer.WriteLine(body); writer.WriteLine("}"); }
private static void writeGenericGetter( TextWriter writer, ModificationField field, bool includeValueParams, bool?includeValidationMethodReturnValue, string body) { CodeGenerationStatics.AddSummaryDocComment(writer, getFormItemGetterSummary(field, "", new string[0])); CodeGenerationStatics.AddParamDocComment(writer, "additionalValidationMethod", "Passes the labelAndSubject and a validator to the function."); CodeGenerationStatics.AddParamDocComment(writer, "validationList", validationListParamDocComment); var parameters = new List <CSharpParameter>(); if (includeValueParams) { parameters.Add(new CSharpParameter("bool", "useValueParameter")); } parameters.Add( new CSharpParameter("System.Func<" + (includeValueParams ? field.NullableTypeName : field.TypeName) + ",string,ControlType>", "controlGetter")); if (includeValidationMethodReturnValue.HasValue) { parameters.Add( includeValidationMethodReturnValue.Value ? new CSharpParameter("System.Func<ControlType,PostBackValueDictionary,string,Validator," + field.TypeName + ">", "validationMethod") : new CSharpParameter("System.Action<ControlType,PostBackValueDictionary,string,Validator>", "validationMethod")); } parameters.Add(new CSharpParameter("string", "labelAndSubject", "\"" + getDefaultLabelAndSubject(field) + "\"")); parameters.Add(new CSharpParameter("FormItemLabel", "labelOverride", "null")); if (includeValueParams) { parameters.Add(new CSharpParameter(field.NullableTypeName, "value", field.TypeIs(typeof(string)) ? "\"\"" : "null")); } parameters.Add(new CSharpParameter("int?", "cellSpan", "null")); parameters.Add(new CSharpParameter("TextAlignment", "textAlignment", "TextAlignment.NotSpecified")); if (includeValidationMethodReturnValue.HasValue) { parameters.Add(new CSharpParameter("System.Func<bool>", "validationPredicate", "null")); parameters.Add(new CSharpParameter("System.Action", "validationErrorNotifier", "null")); parameters.Add(new CSharpParameter("System.Action<string,Validator>", "additionalValidationMethod", "null")); parameters.Add(new CSharpParameter("ValidationList", "validationList", "null")); } writer.WriteLine( "public FormItem<ControlType> " + StandardLibraryMethods.GetCSharpIdentifierSimple("Get" + field.PascalCasedName + "FormItem") + "<ControlType>( " + parameters.Select(i => i.MethodSignatureDeclaration).GetCommaDelimitedStringFromCollection() + " ) where ControlType: Control {"); writer.WriteLine(body); writer.WriteLine("}"); }
private static void writeFormItemGetterWithValueParams( TextWriter writer, string controlType, ModificationField field, string controlTypeForName, string valueParamTypeName, string valueParamDefaultValue, IEnumerable <CSharpParameter> requiredControlParams, IEnumerable <CSharpParameter> requiredValidationParams, IEnumerable <CSharpParameter> optionalControlParams, IEnumerable <CSharpParameter> optionalValidationParams, string preFormItemGetterStatements, string controlGetterExpressionOrBlock, string validationMethodExpressionOrBlock, string labelOverrideNullCoalescingExpression, string postFormItemGetterStatements, IEnumerable <string> additionalSummarySentences) { var validationMethod = "( control, postBackValues, subject, validator ) => " + validationMethodExpressionOrBlock; var formItemGetterStatement = "var formItem = " + StandardLibraryMethods.GetCSharpIdentifierSimple("Get" + field.PascalCasedName + "FormItem") + "( useValueParameter, ( v, ls ) => " + controlGetterExpressionOrBlock + (validationMethodExpressionOrBlock.Any() ? ", " + validationMethod : "") + ", labelAndSubject: labelAndSubject, labelOverride: labelOverride" + labelOverrideNullCoalescingExpression.PrependDelimiter(" ?? ") + ", value: value, cellSpan: cellSpan, textAlignment: textAlignment" + (validationMethodExpressionOrBlock.Any() ? ", validationPredicate: validationPredicate, validationErrorNotifier: validationErrorNotifier, additionalValidationMethod: additionalValidationMethod, validationList: validationList" : "") + " );"; writeFormItemGetter( writer, controlType, field, controlTypeForName, valueParamTypeName, requiredControlParams, requiredValidationParams, valueParamDefaultValue, optionalControlParams, validationMethodExpressionOrBlock.Any(), optionalValidationParams, StringTools.ConcatenateWithDelimiter( Environment.NewLine, preFormItemGetterStatements, formItemGetterStatement, postFormItemGetterStatements, "return formItem;"), additionalSummarySentences); }
private void generateLibraryCode(DevelopmentInstallation installation) { var libraryGeneratedCodeFolderPath = StandardLibraryMethods.CombinePaths(installation.DevelopmentInstallationLogic.LibraryPath, "Generated Code"); Directory.CreateDirectory(libraryGeneratedCodeFolderPath); var isuFilePath = StandardLibraryMethods.CombinePaths(libraryGeneratedCodeFolderPath, "ISU.cs"); IoMethods.DeleteFile(isuFilePath); using (TextWriter writer = new StreamWriter(isuFilePath)) { // Don't add "using System" here. It will create a huge number of ReSharper warnings in the generated code file. writer.WriteLine("using System.Collections.Generic;"); writer.WriteLine("using System.Data;"); // Necessary for stored procedure logic writer.WriteLine("using System.Data.Common;"); writer.WriteLine("using System.Diagnostics;"); // Necessary for ServerSideConsoleAppStatics writer.WriteLine("using System.Linq;"); writer.WriteLine("using System.Reflection;"); writer.WriteLine("using System.Runtime.InteropServices;"); writer.WriteLine("using System.Web.UI;"); writer.WriteLine("using System.Web.UI.WebControls;"); writer.WriteLine("using RedStapler.StandardLibrary;"); writer.WriteLine("using RedStapler.StandardLibrary.Caching;"); writer.WriteLine("using RedStapler.StandardLibrary.Collections;"); // Necessary for row constants writer.WriteLine("using RedStapler.StandardLibrary.DataAccess;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.CommandWriting;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.CommandWriting.Commands;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.CommandWriting.InlineConditionAbstraction;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.CommandWriting.InlineConditionAbstraction.Conditions;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.RetrievalCaching;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.RevisionHistory;"); writer.WriteLine("using RedStapler.StandardLibrary.DataAccess.StandardModification;"); writer.WriteLine("using RedStapler.StandardLibrary.EnterpriseWebFramework;"); writer.WriteLine("using RedStapler.StandardLibrary.EnterpriseWebFramework.Controls;"); writer.WriteLine("using RedStapler.StandardLibrary.Validation;"); writer.WriteLine(); writeAssemblyInfo(writer, installation, "Library"); writer.WriteLine(); var recognizedInstallation = installation as RecognizedDevelopmentInstallation; if (ConfigurationLogic.SystemProviderExists && !installation.DevelopmentInstallationLogic.SystemIsEwl && (recognizedInstallation == null || !recognizedInstallation.SystemIsEwlCacheCoordinator)) { generateGeneralProvider(writer, installation); } if (installation.ExistingInstallationLogic.RuntimeConfiguration.WebApplications.Any()) { writer.WriteLine(); writer.WriteLine("namespace " + installation.DevelopmentInstallationLogic.DevelopmentConfiguration.LibraryNamespaceAndAssemblyName + " {"); writer.WriteLine("public static class WebApplicationNames {"); foreach (var i in installation.ExistingInstallationLogic.RuntimeConfiguration.WebApplications) { writer.WriteLine( "public const string {0} = \"{1}\";".FormatWith(StandardLibraryMethods.GetCSharpIdentifierSimple(i.Name.EnglishToPascal()), i.Name)); } writer.WriteLine("}"); writer.WriteLine("}"); } writer.WriteLine(); TypedCssClassStatics.Generate( installation.GeneralLogic.Path, installation.DevelopmentInstallationLogic.DevelopmentConfiguration.LibraryNamespaceAndAssemblyName, writer); writer.WriteLine(); generateServerSideConsoleAppStatics(writer, installation); generateDataAccessCode(writer, installation); } }
private static void writeColumnValueAssignmentsFromParameters( IEnumerable<Column> columns, string modObjectName ) { foreach( var column in columns ) { writer.WriteLine( modObjectName + "." + getColumnFieldName( column ) + ".Value = @" + StandardLibraryMethods.GetCSharpIdentifierSimple( column.CamelCasedName ) + ";" ); } }
private static void writeExecuteInsertOrUpdateMethod( DBConnection cn, string tableName, bool isRevisionHistoryClass, IEnumerable<Column> keyColumns, Column identityColumn) { writer.WriteLine( "private void executeInsertOrUpdate() {" ); writer.WriteLine( "try {" ); if( isRevisionHistoryClass ) writer.WriteLine( DataAccessStatics.GetConnectionExpression( database ) + ".ExecuteInTransaction( delegate {" ); // insert writer.WriteLine( "if( modType == ModificationType.Insert ) {" ); // If this is a revision history table, write code to insert a new revision when a row is inserted into this table. if( isRevisionHistoryClass ) { writer.WriteLine( "var revisionHistorySetup = (RevisionHistoryProvider)DataAccessStatics.SystemProvider;" ); writer.WriteLine( getColumnFieldName( columns.PrimaryKeyAndRevisionIdColumn ) + ".Value = revisionHistorySetup.GetNextMainSequenceValue();" ); writer.WriteLine( "revisionHistorySetup.InsertRevision( System.Convert.ToInt32( " + getColumnFieldName( columns.PrimaryKeyAndRevisionIdColumn ) + ".Value ), System.Convert.ToInt32( " + getColumnFieldName( columns.PrimaryKeyAndRevisionIdColumn ) + ".Value ), " + DataAccessStatics.GetConnectionExpression( database ) + ".GetUserTransactionId() );" ); } writer.WriteLine( "var insert = new InlineInsert( \"" + tableName + "\" );" ); writer.WriteLine( "addColumnModifications( insert );" ); if( identityColumn != null ) { // One reason the ChangeType call is necessary: SQL Server identities always come back as decimal, and you can't cast a boxed decimal to an int. writer.WriteLine( "{0}.Value = {1};".FormatWith( getColumnFieldName( identityColumn ), identityColumn.GetIncomingValueConversionExpression( "StandardLibraryMethods.ChangeType( insert.Execute( {0} ), typeof( {1} ) )".FormatWith( DataAccessStatics.GetConnectionExpression( database ), identityColumn.UnconvertedDataTypeName ) ) ) ); } else writer.WriteLine( "insert.Execute( " + DataAccessStatics.GetConnectionExpression( database ) + " );" ); // Future calls to Execute should perform updates, not inserts. Use the values of key columns as conditions. writer.WriteLine( "modType = ModificationType.Update;" ); writer.WriteLine( "conditions = new List<" + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + ">();" ); foreach( var column in keyColumns ) { writer.WriteLine( "conditions.Add( new " + DataAccessStatics.GetEqualityConditionClassName( cn, database, tableName, column ) + "( " + StandardLibraryMethods.GetCSharpIdentifierSimple( column.PascalCasedNameExceptForOracle ) + " ) );" ); } writer.WriteLine( "}" ); // if insert // update writer.WriteLine( "else {" ); if( isRevisionHistoryClass ) writer.WriteLine( "copyLatestRevisions( conditions );" ); writer.WriteLine( "var update = new InlineUpdate( \"" + tableName + "\" );" ); writer.WriteLine( "addColumnModifications( update );" ); writer.WriteLine( "conditions.ForEach( condition => update.AddCondition( condition.CommandCondition ) );" ); if( isRevisionHistoryClass ) writer.WriteLine( "update.AddCondition( getLatestRevisionsCondition() );" ); writer.WriteLine( "update.Execute( " + DataAccessStatics.GetConnectionExpression( database ) + " );" ); writer.WriteLine( "}" ); // else if( isRevisionHistoryClass ) writer.WriteLine( "} );" ); // cn.ExecuteInTransaction writer.WriteLine( "}" ); // try writer.WriteLine( "catch( System.Exception e ) {" ); writer.WriteLine( "rethrowAsDataModificationExceptionIfNecessary( e );" ); writer.WriteLine( "throw;" ); writer.WriteLine( "}" ); // catch writer.WriteLine( "}" ); // method }
private static string getColumnFieldName( Column column ) { return StandardLibraryMethods.GetCSharpIdentifierSimple( column.CamelCasedName + "ColumnValue" ); }
internal static void WriteRowClasses(TextWriter writer, IEnumerable <Column> columns, Action <TextWriter> toModificationMethodWriter) { // BasicRow writer.WriteLine("internal class BasicRow {"); foreach (var column in columns.Where(i => !i.IsRowVersion)) { writer.WriteLine("private readonly " + column.DataTypeName + " " + getMemberVariableName(column) + ";"); } writer.WriteLine("internal BasicRow( DbDataReader reader ) {"); foreach (var column in columns.Where(i => !i.IsRowVersion)) { writer.WriteLine("{0} = {1};".FormatWith(getMemberVariableName(column), column.GetDataReaderValueExpression("reader"))); } writer.WriteLine("}"); foreach (var column in columns.Where(i => !i.IsRowVersion)) { writer.WriteLine( "internal " + column.DataTypeName + " " + StandardLibraryMethods.GetCSharpIdentifierSimple(column.PascalCasedName) + " { get { return " + getMemberVariableName(column) + "; } }"); } writer.WriteLine("}"); // Row CodeGenerationStatics.AddSummaryDocComment(writer, "Holds data for a row of this result."); writer.WriteLine("public partial class Row: System.IEquatable<Row> {"); writer.WriteLine("private readonly BasicRow __basicRow;"); writer.WriteLine("internal Row( BasicRow basicRow ) {"); writer.WriteLine("__basicRow = basicRow;"); writer.WriteLine("}"); foreach (var column in columns.Where(i => !i.IsRowVersion)) { writeColumnProperty(writer, column); } // NOTE: Being smarter about the hash code could make searches of the collection faster. writer.WriteLine("public override int GetHashCode() { "); // NOTE: Catch an exception generated by not having any uniquely identifying columns and rethrow it as a UserCorrectableException. writer.WriteLine( "return " + StandardLibraryMethods.GetCSharpIdentifierSimple(columns.First(c => c.UseToUniquelyIdentifyRow).PascalCasedNameExceptForOracle) + ".GetHashCode();"); writer.WriteLine("}"); // Object override of GetHashCode writer.WriteLine(@" public static bool operator == ( Row row1, Row row2 ) { return Equals( row1, row2 ); } public static bool operator !=( Row row1, Row row2 ) { return !Equals( row1, row2 ); }" ); writer.WriteLine("public override bool Equals( object obj ) {"); writer.WriteLine("return Equals( obj as Row );"); writer.WriteLine("}"); // Object override of Equals writer.WriteLine("public bool Equals( Row other ) {"); writer.WriteLine("if( other == null ) return false;"); var condition = ""; foreach (var column in columns.Where(c => c.UseToUniquelyIdentifyRow)) { condition = StringTools.ConcatenateWithDelimiter( " && ", condition, StandardLibraryMethods.GetCSharpIdentifierSimple(column.PascalCasedNameExceptForOracle) + " == other." + StandardLibraryMethods.GetCSharpIdentifierSimple(column.PascalCasedNameExceptForOracle)); } writer.WriteLine("return " + condition + ";"); writer.WriteLine("}"); // Equals method toModificationMethodWriter(writer); writer.WriteLine("}"); // class }
private static string getMemberVariableName(Column column) { // A single underscore is a pretty common thing for other code generators and even some developers to use, so two is more unique and avoids problems. return(StandardLibraryMethods.GetCSharpIdentifierSimple("__" + column.CamelCasedName)); }
internal static void Generate( DBConnection cn, TextWriter writer, string namespaceDeclaration, Database database, RedStapler.StandardLibrary.Configuration.SystemDevelopment.Database configuration) { writer.WriteLine(namespaceDeclaration); foreach (var table in DatabaseOps.GetDatabaseTables(database)) { CodeGenerationStatics.AddSummaryDocComment(writer, "Contains logic that retrieves rows from the " + table + " table."); writer.WriteLine("public static partial class " + GetClassName(cn, table) + " {"); var isRevisionHistoryTable = DataAccessStatics.IsRevisionHistoryTable(table, configuration); var columns = new TableColumns(cn, table, isRevisionHistoryTable); // Write nested classes. DataAccessStatics.WriteRowClasses( writer, columns.AllColumns, localWriter => { if (!columns.DataColumns.Any()) { return; } var modClass = database.SecondaryDatabaseName + "Modification." + StandardModificationStatics.GetClassName(cn, table, isRevisionHistoryTable, isRevisionHistoryTable); var revisionHistorySuffix = StandardModificationStatics.GetRevisionHistorySuffix(isRevisionHistoryTable); writer.WriteLine("public " + modClass + " ToModification" + revisionHistorySuffix + "() {"); writer.WriteLine( "return " + modClass + ".CreateForSingleRowUpdate" + revisionHistorySuffix + "( " + StringTools.ConcatenateWithDelimiter( ", ", columns.AllColumnsExceptRowVersion.Select(i => StandardLibraryMethods.GetCSharpIdentifierSimple(i.PascalCasedNameExceptForOracle)).ToArray()) + " );"); writer.WriteLine("}"); }); writeCacheClass(cn, writer, database, table, columns, isRevisionHistoryTable); var isSmallTable = configuration.SmallTables != null && configuration.SmallTables.Any(i => i.EqualsIgnoreCase(table)); var tableUsesRowVersionedCaching = configuration.TablesUsingRowVersionedDataCaching != null && configuration.TablesUsingRowVersionedDataCaching.Any(i => i.EqualsIgnoreCase(table)); if (tableUsesRowVersionedCaching && columns.RowVersionColumn == null && !(cn.DatabaseInfo is OracleInfo)) { throw new UserCorrectableException( cn.DatabaseInfo is MySqlInfo ? "Row-versioned data caching cannot currently be used with MySQL databases." : "Row-versioned data caching can only be used with the {0} table if you add a rowversion column.".FormatWith(table)); } if (isSmallTable) { writeGetAllRowsMethod(writer, isRevisionHistoryTable, false); } writeGetRowsMethod(cn, writer, database, table, columns, isSmallTable, tableUsesRowVersionedCaching, isRevisionHistoryTable, false); if (isRevisionHistoryTable) { if (isSmallTable) { writeGetAllRowsMethod(writer, true, true); } writeGetRowsMethod(cn, writer, database, table, columns, isSmallTable, tableUsesRowVersionedCaching, true, true); } if (columns.KeyColumns.Count() == 1 && columns.KeyColumns.Single().Name.ToLower().EndsWith("id")) { writeGetRowMatchingIdMethod(cn, writer, database, table, columns, isSmallTable, tableUsesRowVersionedCaching, isRevisionHistoryTable); } if (isRevisionHistoryTable) { DataAccessStatics.WriteGetLatestRevisionsConditionMethod(writer, columns.PrimaryKeyAndRevisionIdColumn.Name); } if (tableUsesRowVersionedCaching) { var keyTupleTypeArguments = getPkAndVersionTupleTypeArguments(cn, columns); writer.WriteLine("private static " + "Cache<System.Tuple<" + keyTupleTypeArguments + ">, BasicRow>" + " getRowsByPkAndVersion() {"); writer.WriteLine( "return AppMemoryCache.GetCacheValue<{0}>( \"{1}\", () => new {0}( i => System.Tuple.Create( {2} ) ) ).RowsByPkAndVersion;".FormatWith( "VersionedRowDataCache<System.Tuple<{0}>, System.Tuple<{1}>, BasicRow>".FormatWith(getPkTupleTypeArguments(columns), keyTupleTypeArguments), database.SecondaryDatabaseName + table.TableNameToPascal(cn) + "TableRetrievalRowsByPkAndVersion", StringTools.ConcatenateWithDelimiter(", ", Enumerable.Range(1, columns.KeyColumns.Count()).Select(i => "i.Item{0}".FormatWith(i)).ToArray()))); writer.WriteLine("}"); } // Initially we did not generate this method for small tables, but we found a need for it when the cache is disabled since that will cause // GetRowMatchingId to repeatedly query. if (columns.KeyColumns.Count() == 1 && columns.KeyColumns.Single().Name.ToLower().EndsWith("id")) { writeToIdDictionaryMethod(writer, columns); } writer.WriteLine("}"); // class } writer.WriteLine("}"); // namespace }
private static void writeResultSetCreatorBody( DBConnection cn, TextWriter writer, Database database, string table, TableColumns tableColumns, bool tableUsesRowVersionedCaching, bool excludesPreviousRevisions, string cacheQueryInDbExpression) { if (tableUsesRowVersionedCaching) { writer.WriteLine("var results = new List<Row>();"); writer.WriteLine(DataAccessStatics.GetConnectionExpression(database) + ".ExecuteInTransaction( delegate {"); // Query for the cache keys of the results. writer.WriteLine( "var keyCommand = {0};".FormatWith( getInlineSelectExpression( table, tableColumns, "{0}, \"{1}\"".FormatWith( StringTools.ConcatenateWithDelimiter(", ", tableColumns.KeyColumns.Select(i => "\"{0}\"".FormatWith(i.Name)).ToArray()), cn.DatabaseInfo is OracleInfo ? "ORA_ROWSCN" : tableColumns.RowVersionColumn.Name), cacheQueryInDbExpression))); writer.WriteLine(getCommandConditionAddingStatement("keyCommand")); writer.WriteLine("var keys = new List<System.Tuple<{0}>>();".FormatWith(getPkAndVersionTupleTypeArguments(cn, tableColumns))); writer.WriteLine( "keyCommand.Execute( " + DataAccessStatics.GetConnectionExpression(database) + ", r => { while( r.Read() ) keys.Add( " + "System.Tuple.Create( {0}, {1} )".FormatWith( StringTools.ConcatenateWithDelimiter( ", ", tableColumns.KeyColumns.Select((c, i) => c.GetDataReaderValueExpression("r", ordinalOverride: i)).ToArray()), cn.DatabaseInfo is OracleInfo ? "({0})r.GetValue( {1} )".FormatWith(oracleRowVersionDataType, tableColumns.KeyColumns.Count()) : tableColumns.RowVersionColumn.GetDataReaderValueExpression("r", ordinalOverride: tableColumns.KeyColumns.Count())) + " ); } );"); writer.WriteLine("var rowsByPkAndVersion = getRowsByPkAndVersion();"); writer.WriteLine("var cachedKeyCount = keys.Where( i => rowsByPkAndVersion.ContainsKey( i ) ).Count();"); // If all but a few results are cached, execute a single-row query for each missing result. writer.WriteLine("if( cachedKeyCount >= keys.Count() - 1 || cachedKeyCount >= keys.Count() * .99 ) {"); writer.WriteLine("foreach( var key in keys ) {"); writer.WriteLine("results.Add( new Row( rowsByPkAndVersion.GetOrAdd( key, () => {"); writer.WriteLine("var singleRowCommand = {0};".FormatWith(getInlineSelectExpression(table, tableColumns, "\"*\"", "false"))); foreach (var i in tableColumns.KeyColumns.Select((c, i) => new { column = c, index = i })) { writer.WriteLine( "singleRowCommand.AddCondition( ( ({0})new {1}( key.Item{2} ) ).CommandCondition );".FormatWith( DataAccessStatics.GetTableConditionInterfaceName(cn, database, table), DataAccessStatics.GetEqualityConditionClassName(cn, database, table, i.column), i.index + 1)); } writer.WriteLine("var singleRowResults = new List<BasicRow>();"); writer.WriteLine( "singleRowCommand.Execute( " + DataAccessStatics.GetConnectionExpression(database) + ", r => { while( r.Read() ) singleRowResults.Add( new BasicRow( r ) ); } );"); writer.WriteLine("return singleRowResults.Single();"); writer.WriteLine("} ) ) );"); writer.WriteLine("}"); writer.WriteLine("}"); // Otherwise, execute the full query. writer.WriteLine("else {"); writer.WriteLine( "var command = {0};".FormatWith( getInlineSelectExpression( table, tableColumns, cn.DatabaseInfo is OracleInfo ? "\"{0}.*\", \"ORA_ROWSCN\"".FormatWith(table) : "\"*\"", cacheQueryInDbExpression))); writer.WriteLine(getCommandConditionAddingStatement("command")); writer.WriteLine("command.Execute( " + DataAccessStatics.GetConnectionExpression(database) + ", r => {"); writer.WriteLine( "while( r.Read() ) results.Add( new Row( rowsByPkAndVersion.GetOrAdd( System.Tuple.Create( {0}, {1} ), () => new BasicRow( r ) ) ) );".FormatWith( StringTools.ConcatenateWithDelimiter(", ", tableColumns.KeyColumns.Select(i => i.GetDataReaderValueExpression("r")).ToArray()), cn.DatabaseInfo is OracleInfo ? "({0})r.GetValue( {1} )".FormatWith(oracleRowVersionDataType, tableColumns.AllColumns.Count()) : tableColumns.RowVersionColumn.GetDataReaderValueExpression("r"))); writer.WriteLine("} );"); writer.WriteLine("}"); writer.WriteLine("} );"); } else { writer.WriteLine("var command = {0};".FormatWith(getInlineSelectExpression(table, tableColumns, "\"*\"", cacheQueryInDbExpression))); writer.WriteLine(getCommandConditionAddingStatement("command")); writer.WriteLine("var results = new List<Row>();"); writer.WriteLine( "command.Execute( " + DataAccessStatics.GetConnectionExpression(database) + ", r => { while( r.Read() ) results.Add( new Row( new BasicRow( r ) ) ); } );"); } // Add all results to RowsByPk. writer.WriteLine("foreach( var i in results ) {"); var pkTupleCreationArgs = tableColumns.KeyColumns.Select(i => "i." + StandardLibraryMethods.GetCSharpIdentifierSimple(i.PascalCasedNameExceptForOracle)); var pkTuple = "System.Tuple.Create( " + StringTools.ConcatenateWithDelimiter(", ", pkTupleCreationArgs.ToArray()) + " )"; writer.WriteLine("cache.RowsByPk[ " + pkTuple + " ] = i;"); if (excludesPreviousRevisions) { writer.WriteLine("cache.LatestRevisionRowsByPk[ " + pkTuple + " ] = i;"); } writer.WriteLine("}"); writer.WriteLine("return results;"); }