internal static void Generate( DBConnection cn, TextWriter writer, string namespaceDeclaration, Database database, 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 (!isRevisionHistoryTable) { return; } writer.WriteLine( "public UserTransaction Transaction { get { return RevisionHistoryStatics.UserTransactionsById[ RevisionHistoryStatics.RevisionsById[ System.Convert.ToInt32( " + EwlStatics.GetCSharpIdentifierSimple(columns.PrimaryKeyAndRevisionIdColumn.PascalCasedNameExceptForOracle) + " ) ].UserTransactionId ]; } }"); }, 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 => EwlStatics.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); } writeGetRowMatchingPkMethod(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." + EwlStatics.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;"); }
internal static void Generate(DBConnection cn, TextWriter writer, string baseNamespace, Database database) { writer.WriteLine("namespace " + baseNamespace + " {"); writer.WriteLine("public static class " + database.SecondaryDatabaseName + "Procedures {"); foreach (var procedure in database.GetProcedures()) { var parameters = database.GetProcedureParameters(procedure); // header CodeGenerationStatics.AddSummaryDocComment(writer, "Executes the " + procedure + " procedure."); var parameterDeclarations = parameters.Select( i => (i.Direction == ParameterDirection.Output ? "out " : i.Direction == ParameterDirection.InputOutput ? "ref " : "") + i.DataTypeName + " " + i.Name); writer.WriteLine("public static void " + procedure + "( " + StringTools.ConcatenateWithDelimiter(", ", parameterDeclarations.ToArray()) + " ) {"); // body writer.WriteLine("var cmd = new SprocExecution( \"" + procedure + "\" );"); foreach (var parameter in parameters) { if (parameter.Direction == ParameterDirection.Input) { writer.WriteLine("cmd.AddParameter( " + getDbCommandParameterCreationExpression(parameter) + " );"); } else { writer.WriteLine("var " + parameter.Name + "Parameter = " + getDbCommandParameterCreationExpression(parameter) + ";"); writer.WriteLine( parameter.Name + "Parameter.GetAdoDotNetParameter( " + DataAccessStatics.GetConnectionExpression(database) + ".DatabaseInfo ).Direction = ParameterDirection." + parameter.Direction + ";"); writer.WriteLine("cmd.AddParameter( " + parameter.Name + "Parameter );"); } } foreach (var parameter in parameters.Where(parameter => parameter.Direction != ParameterDirection.Input)) { writer.WriteLine(parameter.DataTypeName + " " + parameter.Name + "Local = default( " + parameter.DataTypeName + " );"); } writer.WriteLine("cmd.ExecuteReader( " + DataAccessStatics.GetConnectionExpression(database) + ", r => {"); foreach (var parameter in parameters.Where(parameter => parameter.Direction != ParameterDirection.Input)) { var adoDotNetParameterValueExpression = "{0}Parameter.GetAdoDotNetParameter( {1}.DatabaseInfo ).Value".FormatWith( parameter.Name, DataAccessStatics.GetConnectionExpression(database)); // We are not sure if this is handling null correctly. When a null comes back via an "out" parameter, we're not sure whether it is represented with // DBNull.Value or in another way. This issue can be resolved as soon as we have a system with stored procedures that we can use for testing. // NOTE: This is a hack. We would like to use a simple cast to convert the value of the database parameter to the method parameter's type, but we // can't because the types in Oracle.DataAccess.Types, like OracleDecimal, do not support any kind of conversion to .NET types when they are boxed. writer.WriteLine( "{0}Local = {1};".FormatWith( parameter.Name, parameter.GetIncomingValueConversionExpression( "EwlStatics.ChangeType( {0}.ToString(), typeof( {1} ) )".FormatWith( adoDotNetParameterValueExpression, parameter.UnconvertedDataTypeName)))); //writer.WriteLine( "{0}Local = {1};".FormatWith( parameter.Name, parameter.GetIncomingValueConversionExpression( adoDotNetParameterValueExpression ) ) ); } writer.WriteLine("} );"); foreach (var parameter in parameters.Where(parameter => parameter.Direction != ParameterDirection.Input)) { writer.WriteLine(parameter.Name + " = " + parameter.Name + "Local;"); } writer.WriteLine("}"); } writer.WriteLine("}"); writer.WriteLine("}"); }
/// <summary> /// Initializes the system. This includes loading application settings from the configuration file. The application name should be scoped within the system. /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library. /// /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far /// it got in init. /// </summary> /// <param name="globalInitializer">The system's global initializer. Do not pass null.</param> /// <param name="appName"></param> /// <param name="isClientSideProgram"></param> /// <param name="useRelativeInstallationPath">Pass true to use a relative path for the installation folder. This means that the folder will be located using /// the working directory rather than the assembly path. Use with caution.</param> /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this /// InitStatics call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be /// available in the application.</param> public static void InitStatics( SystemInitializer globalInitializer, string appName, bool isClientSideProgram, bool useRelativeInstallationPath = false, Func <DataAccessState> mainDataAccessStateGetter = null) { var initializationLog = "Starting init"; try { if (initialized) { throw new ApplicationException("This class can only be initialized once."); } if (globalInitializer == null) { throw new ApplicationException("The system must have a global initializer."); } // Initialize ConfigurationStatics, including the general provider, before the exception handling block below because it's reasonable for the exception // handling to depend on this. ConfigurationStatics.Init(useRelativeInstallationPath, globalInitializer.GetType(), appName, isClientSideProgram, ref initializationLog); // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works. initialized = true; initializationLog += Environment.NewLine + "Succeeded in primary init."; } catch (Exception e) { initializationLog += Environment.NewLine + e; EwlStatics.EmergencyLog("Initialization log", initializationLog); throw; } try { var asposeLicense = ConfigurationStatics.SystemGeneralProvider.AsposeLicenseName; if (asposeLicense.Any()) { new Aspose.Pdf.License().SetLicense(asposeLicense); new Aspose.Words.License().SetLicense(asposeLicense); } AppMemoryCache.Init(); BlobFileOps.Init(); DataAccessStatics.Init(); DataAccessState.Init(mainDataAccessStateGetter); EmailStatics.Init(); EncryptionOps.Init(); HtmlBlockStatics.Init(); InstallationSupportUtility.ConfigurationLogic.Init1(); UserManagementStatics.Init(); GlobalInitializationOps.globalInitializer = globalInitializer; globalInitializer.InitStatics(); } catch (Exception e) { secondaryInitFailed = true; // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to // automatically restart themselves. Other apps could find this knowledge useful as well. try { TelemetryStatics.ReportError("An exception occurred during application initialization:", e); } catch {} } }
private static string getQueryCacheName( Configuration.SystemDevelopment.Query query, Configuration.SystemDevelopment.QueryPostSelectFromClause postSelectFromClause, bool getFieldName) { return((getFieldName ? "rows" : "Rows") + postSelectFromClause.name + (DataAccessStatics.GetNamedParamList(info, query.selectFromClause + " " + postSelectFromClause.Value).Any() ? "Queries" : "Query")); }
/// <summary> /// Initializes the system. This includes loading application settings from the configuration file. The application name should be scoped within the system. /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library. /// /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far /// it got in init. /// </summary> /// <param name="globalInitializer">The system's global initializer. Do not pass null.</param> /// <param name="appName"></param> /// <param name="isClientSideApp"></param> /// <param name="assemblyFolderPath">Pass a nonempty string to override the assembly folder path, which is used to locate the installation folder. Use with /// caution.</param> /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this /// InitStatics call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be /// available in the application.</param> /// <param name="useLongDatabaseTimeouts">Pass true if the application is a background process that can tolerate slow database access.</param> public static void InitStatics( SystemInitializer globalInitializer, string appName, bool isClientSideApp, string assemblyFolderPath = "", Func <DataAccessState> mainDataAccessStateGetter = null, bool useLongDatabaseTimeouts = false) { var initializationLog = "Starting init"; try { if (initialized) { throw new ApplicationException("This class can only be initialized once."); } if (globalInitializer == null) { throw new ApplicationException("The system must have a global initializer."); } // Initialize these before the exception handling block below because it's reasonable for the exception handling to depend on them. ConfigurationStatics.Init(assemblyFolderPath, globalInitializer.GetType(), appName, isClientSideApp, ref initializationLog); EmailStatics.Init(); TelemetryStatics.Init(); // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works. initialized = true; initializationLog += Environment.NewLine + "Succeeded in primary init."; } catch (Exception e) { initializationLog += Environment.NewLine + e; EwlStatics.EmergencyLog("Initialization log", initializationLog); throw; } try { CultureInfo.DefaultThreadCurrentCulture = Cultures.EnglishUnitedStates; JsonConvert.DefaultSettings = () => new JsonSerializerSettings().ConfigureForNodaTime(DateTimeZoneProviders.Tzdb); var asposePdfLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.PDF.lic"); if (File.Exists(asposePdfLicensePath)) { new Aspose.Pdf.License().SetLicense(asposePdfLicensePath); } var asposeWordsLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.Words.lic"); if (File.Exists(asposeWordsLicensePath)) { new Aspose.Words.License().SetLicense(asposeWordsLicensePath); } AppMemoryCache.Init(); BlobStorageStatics.Init(); DataAccessStatics.Init(); DataAccessState.Init(mainDataAccessStateGetter, useLongDatabaseTimeouts); EncryptionOps.Init(); HtmlBlockStatics.Init(); UserManagementStatics.Init( () => { if (ExternalFunctionalityStatics.SamlFunctionalityEnabled) { ExternalFunctionalityStatics.ExternalSamlProvider.RefreshConfiguration(); } }); ExternalFunctionalityStatics.Init(); GlobalInitializationOps.globalInitializer = globalInitializer; globalInitializer.InitStatics(); UserManagementStatics.InitSystemSpecificLogicDependencies(); } catch (Exception e) { secondaryInitFailed = true; // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to // automatically restart themselves. Other apps could find this knowledge useful as well. try { TelemetryStatics.ReportError("An exception occurred during application initialization:", e); } catch {} } }
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 getConditionParameterDeclarations( DBConnection cn, string tableName ) { return "" + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + " requiredCondition, params " + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + "[] additionalConditions"; }
private static void writeCreateForUpdateMethod( DBConnection cn, string tableName, bool isRevisionHistoryTable, bool isRevisionHistoryClass, string methodNameSuffix) { // header CodeGenerationStatics.AddSummaryDocComment( writer, "Creates a modification object in update mode with the specified conditions, which can be used to do a piecemeal update of the " + tableName + " table." ); writer.WriteLine( "public static " + GetClassName( cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass ) + " CreateForUpdate" + methodNameSuffix + "( " + getConditionParameterDeclarations( cn, tableName ) + " ) {" ); // body writer.WriteLine( "var mod = new " + GetClassName( cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass ) + " { modType = ModificationType.Update, conditions = getConditionList( requiredCondition, additionalConditions ) };" ); // Set column values that correspond to modification conditions to the values of those conditions. One reason this is important is so the primary // key can be retrieved in a consistent way regardless of whether the modification object is an insert or an update. writer.WriteLine( "foreach( var condition in mod.conditions ) {" ); var prefix = "if"; foreach( var column in columns.AllColumnsExceptRowVersion ) { writer.WriteLine( prefix + "( condition is " + DataAccessStatics.GetEqualityConditionClassName( cn, database, tableName, column ) + " )" ); writer.WriteLine( "mod." + getColumnFieldName( column ) + ".Value = ( condition as " + DataAccessStatics.GetEqualityConditionClassName( cn, database, tableName, column ) + " ).Value;" ); prefix = "else if"; } writer.WriteLine( "}" ); writer.WriteLine( writer.NewLine + "mod.markColumnValuesUnchanged();" ); writer.WriteLine( "return mod;" ); writer.WriteLine( "}" ); }
private static void writeCopyLatestRevisionsMethod( DBConnection cn, string tableName, IEnumerable<Column> nonIdentityColumns ) { writer.WriteLine( "private static void copyLatestRevisions( List<" + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + "> conditions ) {" ); writer.WriteLine( "var revisionHistorySetup = (RevisionHistoryProvider)DataAccessStatics.SystemProvider;" ); writer.WriteLine( "var command = new InlineSelect( \"" + columns.PrimaryKeyAndRevisionIdColumn.Name + "\".ToSingleElementArray(), \"FROM " + tableName + "\", false );" ); writer.WriteLine( "conditions.ForEach( condition => command.AddCondition( condition.CommandCondition ) );" ); writer.WriteLine( "command.AddCondition( getLatestRevisionsCondition() );" ); writer.WriteLine( "var latestRevisionIds = new List<int>();" ); writer.WriteLine( "command.Execute( " + DataAccessStatics.GetConnectionExpression( database ) + ", r => { while( r.Read() ) latestRevisionIds.Add( System.Convert.ToInt32( r[0] ) ); } );" ); writer.WriteLine( "foreach( var latestRevisionId in latestRevisionIds ) {" ); // Get the latest revision. writer.WriteLine( "var latestRevision = revisionHistorySetup.GetRevision( latestRevisionId );" ); // If this condition is true, we've already modified the row in this transaction. If we were to copy it, we'd end up with two revisions of the same entity // in the same user transaction, which we don't support. writer.WriteLine( "if( latestRevision.UserTransactionId == " + DataAccessStatics.GetConnectionExpression( database ) + ".GetUserTransactionId() )" ); writer.WriteLine( "continue;" ); // Update the latest revision with a new user transaction. writer.WriteLine( "revisionHistorySetup.UpdateRevision( latestRevisionId, latestRevisionId, " + DataAccessStatics.GetConnectionExpression( database ) + ".GetUserTransactionId(), latestRevisionId );" ); // Insert a copy of the latest revision with a new ID. This will represent the revision of the data before it was changed. writer.WriteLine( "var copiedRevisionId = revisionHistorySetup.GetNextMainSequenceValue();" ); writer.WriteLine( "revisionHistorySetup.InsertRevision( copiedRevisionId, latestRevisionId, latestRevision.UserTransactionId );" ); // Insert a copy of the data row and make it correspond to the copy of the latest revision. writer.WriteLine( "var copyCommand = " + DataAccessStatics.GetConnectionExpression( database ) + ".DatabaseInfo.CreateCommand();" ); writer.WriteLine( "copyCommand.CommandText = \"INSERT INTO " + tableName + " SELECT \";" ); foreach( var column in nonIdentityColumns ) { if( column == columns.PrimaryKeyAndRevisionIdColumn ) { writer.WriteLine( "var revisionIdParameter = new DbCommandParameter( \"copiedRevisionId\", new DbParameterValue( copiedRevisionId ) );" ); writer.WriteLine( "copyCommand.CommandText += revisionIdParameter.GetNameForCommandText( " + DataAccessStatics.GetConnectionExpression( database ) + ".DatabaseInfo ) + \", \";" ); writer.WriteLine( "copyCommand.Parameters.Add( revisionIdParameter.GetAdoDotNetParameter( " + DataAccessStatics.GetConnectionExpression( database ) + ".DatabaseInfo ) );" ); } else writer.WriteLine( "copyCommand.CommandText += \"" + column.Name + ", \";" ); } writer.WriteLine( "copyCommand.CommandText = copyCommand.CommandText.Remove( copyCommand.CommandText.Length - 2 );" ); writer.WriteLine( "copyCommand.CommandText += \" FROM " + tableName + " WHERE \";" ); writer.WriteLine( "( new EqualityCondition( new InlineDbCommandColumnValue( \"" + columns.PrimaryKeyAndRevisionIdColumn.Name + "\", new DbParameterValue( latestRevisionId ) ) ) as InlineDbCommandCondition ).AddToCommand( copyCommand, " + DataAccessStatics.GetConnectionExpression( database ) + ".DatabaseInfo, \"latestRevisionId\" );" ); writer.WriteLine( DataAccessStatics.GetConnectionExpression( database ) + ".ExecuteNonQueryCommand( copyCommand );" ); writer.WriteLine( "}" ); // foreach writer.WriteLine( "}" ); // method }
private static void writeClass(DBConnection cn, string tableName, bool isRevisionHistoryTable, bool isRevisionHistoryClass, int?commandTimeoutSeconds) { columns = new TableColumns(cn, tableName, isRevisionHistoryClass); writer.WriteLine("public partial class " + GetClassName(cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass) + " {"); var revisionHistorySuffix = GetRevisionHistorySuffix(isRevisionHistoryClass); // Write public static methods. writeInsertRowMethod(tableName, revisionHistorySuffix, "", columns.KeyColumns); writeInsertRowMethod(tableName, revisionHistorySuffix, "WithoutAdditionalLogic", columns.KeyColumns); writeUpdateRowsMethod(cn, tableName, revisionHistorySuffix, ""); writeUpdateRowsMethod(cn, tableName, revisionHistorySuffix, "WithoutAdditionalLogic"); writeDeleteRowsMethod(cn, tableName, revisionHistorySuffix, true); writeDeleteRowsMethod(cn, tableName, revisionHistorySuffix + "WithoutAdditionalLogic", false); writePrivateDeleteRowsMethod(cn, tableName, isRevisionHistoryClass, commandTimeoutSeconds); writer.WriteLine( "static partial void preDelete( List<" + DataAccessStatics.GetTableConditionInterfaceName(cn, database, tableName) + "> conditions, ref " + getPostDeleteCallClassName(cn, tableName) + " postDeleteCall );"); writer.WriteLine("private ModificationType modType;"); writer.WriteLine("private List<" + DataAccessStatics.GetTableConditionInterfaceName(cn, database, tableName) + "> conditions;"); foreach (var column in columns.AllColumnsExceptRowVersion) { writeFieldsAndPropertiesForColumn(column); } //foreach( var column in columns.DataColumns.Where( i => !columns.KeyColumns.Contains( i ) ) ) // FormItemStatics.WriteFormItemGetters( writer, column.GetModificationField() ); // Write constructors. writeCreateForInsertMethod(cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass, revisionHistorySuffix); writeCreateForUpdateMethod(cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass, revisionHistorySuffix); if (columns.DataColumns.Any()) { writeCreateForSingleRowUpdateMethod(cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass, revisionHistorySuffix); } writeGetConditionListMethod(cn, tableName); writer.WriteLine("private " + GetClassName(cn, tableName, isRevisionHistoryTable, isRevisionHistoryClass) + "() {}"); if (columns.DataColumns.Any()) { writeSetAllDataMethod(); } // Write execute methods and helpers. writeExecuteMethod(tableName); writer.WriteLine("partial void preInsert();"); writer.WriteLine("partial void preUpdate();"); writeExecuteWithoutAdditionalLogicMethod(tableName); writeExecuteInsertOrUpdateMethod(cn, tableName, isRevisionHistoryClass, columns.KeyColumns, columns.IdentityColumn, commandTimeoutSeconds); writeAddColumnModificationsMethod(columns.AllNonIdentityColumnsExceptRowVersion); if (isRevisionHistoryClass) { writeCopyLatestRevisionsMethod(cn, tableName, columns.AllNonIdentityColumnsExceptRowVersion, commandTimeoutSeconds); DataAccessStatics.WriteGetLatestRevisionsConditionMethod(writer, columns.PrimaryKeyAndRevisionIdColumn.Name); } writeRethrowAsEwfExceptionIfNecessary(); writer.WriteLine( "static partial void populateConstraintNamesToViolationErrorMessages( Dictionary<string,string> constraintNamesToViolationErrorMessages );"); writer.WriteLine("partial void postInsert();"); writer.WriteLine("partial void postUpdate();"); writeMarkColumnValuesUnchangedMethod(); writer.WriteLine("}"); }
private static string getQueryCacheType(Query query, QueryPostSelectFromClause postSelectFromClause) => DataAccessStatics.GetNamedParamList(info, query.selectFromClause + " " + postSelectFromClause.Value).Any() ? "QueryRetrievalQueryCache<Row>" : "ParameterlessQueryCache<Row>";
private static string getQueryCacheName(Query query, QueryPostSelectFromClause postSelectFromClause, bool getFieldName) => (getFieldName ? "rows" : "Rows") + postSelectFromClause.name + (DataAccessStatics.GetNamedParamList(info, query.selectFromClause + " " + postSelectFromClause.Value).Any() ? "Queries" : "Query");