private static void writePrivateDeleteRowsMethod( DBConnection cn, string tableName, bool isRevisionHistoryClass ) { // NOTE: For revision history tables, we should have the delete method automatically clean up the revisions table (but not user transactions) for us when doing direct-with-revision-bypass deletions. writer.WriteLine( "private static int deleteRows( List<" + DataAccessStatics.GetTableConditionInterfaceName( cn, database, tableName ) + "> conditions ) {" ); if( isRevisionHistoryClass ) writer.WriteLine( "return " + DataAccessStatics.GetConnectionExpression( database ) + ".ExecuteInTransaction( () => {" ); if( isRevisionHistoryClass ) writer.WriteLine( "copyLatestRevisions( conditions );" ); writer.WriteLine( "var delete = new InlineDelete( \"" + tableName + "\" );" ); writer.WriteLine( "conditions.ForEach( condition => delete.AddCondition( condition.CommandCondition ) );" ); if( isRevisionHistoryClass ) writer.WriteLine( "delete.AddCondition( getLatestRevisionsCondition() );" ); writer.WriteLine( "try {" ); writer.WriteLine( "return delete.Execute( " + DataAccessStatics.GetConnectionExpression( database ) + " );" ); writer.WriteLine( "}" ); // try writer.WriteLine( "catch( System.Exception e ) {" ); writer.WriteLine( "rethrowAsDataModificationExceptionIfNecessary( e );" ); writer.WriteLine( "throw;" ); writer.WriteLine( "}" ); // catch if( isRevisionHistoryClass ) writer.WriteLine( "} );" ); // cn.ExecuteInTransaction writer.WriteLine( "}" ); }
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) + "( " + EwlStatics.GetCSharpIdentifier(column.CamelCasedName) + " ) );"); } writeColumnValueAssignmentsFromParameters(columns.AllColumnsExceptRowVersion, "mod"); writer.WriteLine("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 ) { 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 ); 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 ); writeAddColumnModificationsMethod( columns.AllNonIdentityColumnsExceptRowVersion ); if( isRevisionHistoryClass ) { writeCopyLatestRevisionsMethod( cn, tableName, columns.AllNonIdentityColumnsExceptRowVersion ); 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 void writeGetRowsMethod( DBConnection cn, TextWriter writer, IDatabase database, string table, TableColumns tableColumns, bool isSmallTable, bool tableUsesRowVersionedCaching, bool isRevisionHistoryTable, bool excludePreviousRevisions, int?commandTimeoutSeconds) { // header var methodName = "GetRows" + (isSmallTable ? "MatchingConditions" : "") + (isRevisionHistoryTable && !excludePreviousRevisions ? "IncludingPreviousRevisions" : ""); CodeGenerationStatics.AddSummaryDocComment( writer, "Retrieves the rows from the table that match the specified conditions, ordered in a stable way." + (isSmallTable ? " Since the table is specified as small, you should only use this method if you cannot filter the rows in code." : "")); writer.WriteLine( "public static IEnumerable<Row> " + methodName + "( params " + DataAccessStatics.GetTableConditionInterfaceName(cn, database, table) + "[] conditions ) {"); // body // If it's a primary key query, use RowsByPk if possible. foreach (var i in tableColumns.KeyColumns) { var equalityConditionClassName = DataAccessStatics.GetEqualityConditionClassName(cn, database, table, i); writer.WriteLine("var {0}Condition = conditions.OfType<{1}>().FirstOrDefault();".FormatWith(i.CamelCasedName, equalityConditionClassName)); } writer.WriteLine("var cache = Cache.Current;"); var pkConditionVariableNames = tableColumns.KeyColumns.Select(i => i.CamelCasedName + "Condition"); writer.WriteLine( "var isPkQuery = " + StringTools.ConcatenateWithDelimiter(" && ", pkConditionVariableNames.Select(i => i + " != null").ToArray()) + " && conditions.Count() == " + tableColumns.KeyColumns.Count() + ";"); writer.WriteLine("if( isPkQuery ) {"); writer.WriteLine("Row row;"); writer.WriteLine( "if( cache." + (excludePreviousRevisions ? "LatestRevision" : "") + $"RowsByPk.TryGetValue( {TypeNames.Tuple}.Create( " + StringTools.ConcatenateWithDelimiter(", ", pkConditionVariableNames.Select(i => i + ".Value").ToArray()) + " ), out row ) )"); writer.WriteLine("return new [] {row};"); writer.WriteLine("}"); var commandConditionsExpression = "conditions.Select( i => i.CommandCondition )"; if (excludePreviousRevisions) { commandConditionsExpression += ".Concat( new [] {getLatestRevisionsCondition()} )"; } writer.WriteLine("return cache.Queries.GetResultSet( " + commandConditionsExpression + ", commandConditions => {"); writeResultSetCreatorBody( cn, writer, database, table, tableColumns, tableUsesRowVersionedCaching, excludePreviousRevisions, "!isPkQuery", commandTimeoutSeconds); writer.WriteLine("} );"); writer.WriteLine("}"); }
private static void writeGetConditionListMethod(DBConnection cn, string tableName) { writer.WriteLine( "private static List<" + DataAccessStatics.GetTableConditionInterfaceName(cn, database, tableName) + "> getConditionList( " + getConditionParameterDeclarations(cn, tableName) + " ) {"); writer.WriteLine("var conditions = new List<" + DataAccessStatics.GetTableConditionInterfaceName(cn, database, tableName) + ">();"); writer.WriteLine("conditions.Add( requiredCondition );"); writer.WriteLine("foreach( var condition in additionalConditions )"); writer.WriteLine("conditions.Add( condition );"); writer.WriteLine("return conditions;"); writer.WriteLine("}"); }
private static void writePrivateDeleteRowsMethod(DBConnection cn, string tableName, bool isRevisionHistoryClass, int?commandTimeoutSeconds) { // NOTE: For revision history tables, we should have the delete method automatically clean up the revisions table (but not user transactions) for us when doing direct-with-revision-bypass deletions. writer.WriteLine("private static int deleteRows( List<" + DataAccessStatics.GetTableConditionInterfaceName(cn, database, tableName) + "> conditions ) {"); if (isRevisionHistoryClass) { writer.WriteLine("return " + DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + ".ExecuteInTransaction( () => {"); } if (isRevisionHistoryClass) { writer.WriteLine("copyLatestRevisions( conditions );"); } writer.WriteLine($@"var delete = new {TypeNames.InlineDelete}( ""{tableName}"", {commandTimeoutSeconds?.ToString() ?? "null"} );"); writer.WriteLine("conditions.ForEach( condition => delete.AddCondition( condition.CommandCondition ) );"); if (isRevisionHistoryClass) { writer.WriteLine("delete.AddCondition( getLatestRevisionsCondition() );"); } writer.WriteLine("try {"); writer.WriteLine("return delete.Execute( " + DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + " );"); writer.WriteLine("}"); // try writer.WriteLine("catch(" + nameof(Exception) + " e) {"); writer.WriteLine("rethrowAsDataModificationExceptionIfNecessary( e );"); writer.WriteLine("throw;"); writer.WriteLine("}"); // catch if (isRevisionHistoryClass) { writer.WriteLine("} );"); // cn.ExecuteInTransaction } writer.WriteLine("}"); }
private static void writeExecuteInsertOrUpdateMethod( DBConnection cn, string tableName, bool isRevisionHistoryClass, IEnumerable <Column> keyColumns, Column identityColumn) { writer.WriteLine("private void executeInsertOrUpdate( bool isLongRunning ) {"); 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 = RevisionHistoryStatics.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("insert.AddColumnModifications( getColumnModificationValues() );"); 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( "EwlStatics.ChangeType( insert.Execute( {0}, isLongRunning: isLongRunning ), typeof( {1} ) )".FormatWith( DataAccessStatics.GetConnectionExpression(database), identityColumn.UnconvertedDataTypeName)))); } else { writer.WriteLine("insert.Execute( {0}, isLongRunning: isLongRunning );".FormatWith(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) + "( " + EwlStatics.GetCSharpIdentifier(column.PascalCasedNameExceptForOracle) + " ) );"); } writer.WriteLine("}"); // if insert // update writer.WriteLine("else {"); writer.WriteLine("var modificationValues = getColumnModificationValues();"); writer.WriteLine("if( modificationValues.Any() ) {"); if (isRevisionHistoryClass) { writer.WriteLine("copyLatestRevisions( conditions, isLongRunning );"); } writer.WriteLine("var update = new InlineUpdate( \"" + tableName + "\" );"); writer.WriteLine("update.AddColumnModifications( modificationValues );"); writer.WriteLine("conditions.ForEach( condition => update.AddCondition( condition.CommandCondition ) );"); if (isRevisionHistoryClass) { writer.WriteLine("update.AddCondition( getLatestRevisionsCondition() );"); } writer.WriteLine("update.Execute( {0}, isLongRunning: isLongRunning );".FormatWith(DataAccessStatics.GetConnectionExpression(database))); writer.WriteLine("}"); 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 writeResultSetCreatorBody( DBConnection cn, TextWriter writer, IDatabase database, string table, TableColumns tableColumns, bool tableUsesRowVersionedCaching, bool excludesPreviousRevisions, string cacheQueryInDbExpression, int?commandTimeoutSeconds) { if (tableUsesRowVersionedCaching) { writer.WriteLine("var results = new List<Row>();"); writer.WriteLine(DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + ".ExecuteInTransaction( () => {"); // 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, commandTimeoutSeconds))); writer.WriteLine(getCommandConditionAddingStatement("keyCommand")); writer.WriteLine($"var keys = new List<{TypeNames.Tuple}<{getPkAndVersionTupleTypeArguments( cn, tableColumns )}>>();"); var concatenateWithDelimiter = StringTools.ConcatenateWithDelimiter( ", ", tableColumns.KeyColumns.Select((c, i) => c.GetDataReaderValueExpression("r", ordinalOverride: i))); var o = cn.DatabaseInfo is OracleInfo ? "({0})r.GetValue( {1} )".FormatWith(oracleRowVersionDataType, tableColumns.KeyColumns.Count()) : tableColumns.RowVersionColumn.GetDataReaderValueExpression("r", ordinalOverride: tableColumns.KeyColumns.Count()); writer.WriteLine( "keyCommand.Execute( " + DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + ", r => { while( r.Read() ) keys.Add( " + $"{TypeNames.Tuple}.Create( {concatenateWithDelimiter}, {o} )" + " ); } );"); 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.CodeBlock( "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", commandTimeoutSeconds))); 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.DataAccessStateCurrentDatabaseConnectionExpression + ", r => { while( r.Read() ) singleRowResults.Add( new BasicRow( r ) ); } );"); writer.WriteLine("return singleRowResults.Single();"); writer.WriteLine("} ) ) );"); writer.WriteLine("}"); }); // Otherwise, execute the full query. writer.CodeBlock( "else {", () => { writer.WriteLine( "var command = {0};".FormatWith( getInlineSelectExpression( table, tableColumns, cn.DatabaseInfo is OracleInfo ? "\"{0}.*\", \"ORA_ROWSCN\"".FormatWith(table) : "\"*\"", cacheQueryInDbExpression, commandTimeoutSeconds))); writer.WriteLine(getCommandConditionAddingStatement("command")); writer.WriteLine("command.Execute( " + DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + ", 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("} );"); } else { writer.WriteLine( "var command = {0};".FormatWith(getInlineSelectExpression(table, tableColumns, @"""*""", cacheQueryInDbExpression, commandTimeoutSeconds))); writer.WriteLine(getCommandConditionAddingStatement("command")); writer.WriteLine("var results = new List<Row>();"); writer.WriteLine( "command.Execute( " + DataAccessStatics.DataAccessStateCurrentDatabaseConnectionExpression + ", 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." + Utility.GetCSharpIdentifier(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;"); }