diff --git a/CodeGenerator/Generators/QueriesGen.cs b/CodeGenerator/Generators/QueriesGen.cs index 917a611e..ddafb45e 100644 --- a/CodeGenerator/Generators/QueriesGen.cs +++ b/CodeGenerator/Generators/QueriesGen.cs @@ -64,7 +64,19 @@ public class {{className}} { {{dbDriver.GetConstructorStatements().JoinByNewLine()}} } - private string {{Variable.ConnectionString.AsPropertyName()}} { get; } + + private {{className}}({{dbDriver.TransactionClassName}} {{Variable.Transaction.AsVarName()}}) + { + {{dbDriver.GetTransactionConstructorStatements().JoinByNewLine()}} + } + + public static {{className}} WithTransaction({{dbDriver.TransactionClassName}} {{Variable.Transaction.AsVarName()}}) + { + return new {{className}}({{Variable.Transaction.AsVarName()}}); + } + + private {{dbDriver.AddNullableSuffixIfNeeded(dbDriver.TransactionClassName, false)}} {{Variable.Transaction.AsPropertyName()}} { get; } + private {{dbDriver.AddNullableSuffixIfNeeded("string", false)}} {{Variable.ConnectionString.AsPropertyName()}} { get; } } """)!; return classDeclaration.AddMembers(classMembers.ToArray()); diff --git a/Drivers/DbDriver.cs b/Drivers/DbDriver.cs index 5e07af1e..0b43dc00 100644 --- a/Drivers/DbDriver.cs +++ b/Drivers/DbDriver.cs @@ -15,6 +15,8 @@ public abstract class DbDriver public string DefaultSchema { get; } + public abstract string TransactionClassName { get; } + public Dictionary> Tables { get; } public Dictionary> Enums { get; } @@ -118,6 +120,16 @@ public virtual string[] GetConstructorStatements() .ToArray(); } + public virtual string[] GetTransactionConstructorStatements() + { + return new List + { + $"this.{Variable.Transaction.AsPropertyName()} = {Variable.Transaction.AsVarName()};" + } + .AppendIf("Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;", Options.UseDapper) + .ToArray(); + } + public virtual MemberDeclarationSyntax[] GetMemberDeclarationsForUtils() { return []; diff --git a/Drivers/Generators/ExecDeclareGen.cs b/Drivers/Generators/ExecDeclareGen.cs index a5c64940..bc061e3b 100644 --- a/Drivers/Generators/ExecDeclareGen.cs +++ b/Drivers/Generators/ExecDeclareGen.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Plugin; +using System.Linq; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace SqlcGenCsharp.Drivers.Generators; @@ -21,40 +22,94 @@ public MemberDeclarationSyntax Generate(string queryTextConstant, string argInte private string GetMethodBody(string queryTextConstant, Query query) { - var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); var sqlTextTransform = CommonGen.GetSqlTransformations(query, queryTextConstant); - return dbDriver.Options.UseDapper ? GetAsDapper() : GetAsDriver(); - - string GetAsDapper() - { - var dapperParamsSection = CommonGen.ConstructDapperParamsDict(query.Params); - var dapperArgs = dapperParamsSection != string.Empty - ? $", {Variable.QueryParams.AsVarName()}" - : string.Empty; - return $$""" - using ({{establishConnection}}) - {{{sqlTextTransform}}{{dapperParamsSection}} - await {{Variable.Connection.AsVarName()}}.ExecuteAsync({{queryTextConstant}}{{dapperArgs}}); + var useDapper = dbDriver.Options.UseDapper; + + var dapperParams = useDapper ? CommonGen.ConstructDapperParamsDict(query.Params) : string.Empty; + var sqlVar = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; + var transactionProperty = Variable.Transaction.AsPropertyName(); + + var noTxBody = useDapper ? GetDapperNoTxBody(sqlVar, query) : GetDriverNoTxBody(sqlVar, query); + var withTxBody = useDapper ? GetDapperWithTxBody(sqlVar, query) : GetDriverWithTxBody(sqlVar, query); + + return $$""" + {{sqlTextTransform}} + {{dapperParams}} + if (this.{{transactionProperty}} == null) + { + {{noTxBody}} + } + {{withTxBody}} + """; + } + + private string GetDapperNoTxBody(string sqlVar, Query query) + { + var (establishConnection, _) = dbDriver.EstablishConnection(query); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + using ({{establishConnection}}) + { + await {{Variable.Connection.AsVarName()}}.ExecuteAsync({{sqlVar}}{{dapperArgs}}); + } + return; + """; + } + + private string GetDapperWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.{{transactionProperty}}.Connection.ExecuteAsync( + {{sqlVar}}{{dapperArgs}}, + transaction: this.{{transactionProperty}}); + """; + } + + private string GetDriverNoTxBody(string sqlVar, Query query) + { + var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); + var createSqlCommand = dbDriver.CreateSqlCommand(sqlVar); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + return $$""" + using ({{establishConnection}}) + { + {{connectionOpen.AppendSemicolonUnlessEmpty()}} + using ({{createSqlCommand}}) + { + {{commandParameters}} + await {{Variable.Command.AsVarName()}}.ExecuteNonQueryAsync(); } - """; - } - - string GetAsDriver() - { - var commandParameters = CommonGen.AddParametersToCommand(query.Params); - var createSqlCommand = dbDriver.CreateSqlCommand(sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant); - var executeScalar = $"await {Variable.Command.AsVarName()}.ExecuteScalarAsync();"; - return $$""" - using ({{establishConnection}}) - { - {{connectionOpen.AppendSemicolonUnlessEmpty()}}{{sqlTextTransform}} - using ({{createSqlCommand}}) - { - {{commandParameters}} - {{executeScalar}} - } - } - """; - } + } + return; + """; + } + + private string GetDriverWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var commandVar = Variable.Command.AsVarName(); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var {{commandVar}} = this.{{transactionProperty}}.Connection.CreateCommand()) + { + {{commandVar}}.CommandText = {{sqlVar}}; + {{commandVar}}.Transaction = this.{{transactionProperty}}; + {{commandParameters}} + await {{commandVar}}.ExecuteNonQueryAsync(); + } + """; } } \ No newline at end of file diff --git a/Drivers/Generators/ExecLastIdDeclareGen.cs b/Drivers/Generators/ExecLastIdDeclareGen.cs index de46f6db..b00964e4 100644 --- a/Drivers/Generators/ExecLastIdDeclareGen.cs +++ b/Drivers/Generators/ExecLastIdDeclareGen.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Plugin; +using System.Linq; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace SqlcGenCsharp.Drivers.Generators; @@ -21,42 +22,92 @@ public MemberDeclarationSyntax Generate(string queryTextConstant, string argInte private string GetMethodBody(string queryTextConstant, Query query) { - var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); var sqlTextTransform = CommonGen.GetSqlTransformations(query, queryTextConstant); - connectionOpen = connectionOpen.AppendSemicolonUnlessEmpty(); - return dbDriver.Options.UseDapper ? GetAsDapper() : GetAsDriver(); - - string GetAsDapper() - { - var dapperParamsSection = CommonGen.ConstructDapperParamsDict(query.Params); - var dapperArgs = dapperParamsSection == string.Empty - ? string.Empty - : $", {Variable.QueryParams.AsVarName()}"; - return $$""" - using ({{establishConnection}}) - {{{sqlTextTransform}}{{dapperParamsSection}} - return await {{Variable.Connection.AsVarName()}}.QuerySingleAsync<{{dbDriver.GetIdColumnType(query)}}>({{queryTextConstant}}{{dapperArgs}}); - } - """; - } - - string GetAsDriver() - { - var sqlTextVar = sqlTextTransform == string.Empty ? queryTextConstant : Variable.TransformedSql.AsVarName(); - var createSqlCommand = dbDriver.CreateSqlCommand(sqlTextVar); - var commandParameters = CommonGen.AddParametersToCommand(query.Params); - var returnLastId = ((IExecLastId)dbDriver).GetLastIdStatement(query).JoinByNewLine(); - return $$""" - using ({{establishConnection}}) - { - {{connectionOpen}}{{sqlTextTransform}} - using ({{createSqlCommand}}) - { + var useDapper = dbDriver.Options.UseDapper; + + var dapperParams = useDapper ? CommonGen.ConstructDapperParamsDict(query.Params) : string.Empty; + var sqlVar = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; + var transactionProperty = Variable.Transaction.AsPropertyName(); + + var noTxBody = useDapper ? GetDapperNoTxBody(sqlVar, query) : GetDriverNoTxBody(sqlVar, query); + var withTxBody = useDapper ? GetDapperWithTxBody(sqlVar, query) : GetDriverWithTxBody(sqlVar, query); + + return $$""" + {{sqlTextTransform}} + {{dapperParams}} + if (this.{{transactionProperty}} == null) + { + {{noTxBody}} + } + {{withTxBody}} + """; + } + + private string GetDapperNoTxBody(string sqlVar, Query query) + { + var (establishConnection, _) = dbDriver.EstablishConnection(query); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + using ({{establishConnection}}) + { + return await {{Variable.Connection.AsVarName()}}.QuerySingleAsync<{{dbDriver.GetIdColumnType(query)}}>({{sqlVar}}{{dapperArgs}}); + } + """; + } + + private string GetDapperWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.{{transactionProperty}}.Connection.QuerySingleAsync<{{dbDriver.GetIdColumnType(query)}}>({{sqlVar}}{{dapperArgs}}, transaction: this.{{transactionProperty}}); + """; + } + + private string GetDriverNoTxBody(string sqlVar, Query query) + { + var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); + var createSqlCommand = dbDriver.CreateSqlCommand(sqlVar); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var returnLastId = ((IExecLastId)dbDriver).GetLastIdStatement(query).JoinByNewLine(); + return $$""" + using ({{establishConnection}}) + { + {{connectionOpen.AppendSemicolonUnlessEmpty()}} + using ({{createSqlCommand}}) + { {{commandParameters}} {{returnLastId}} - } - } - """; - } + } + } + """; + } + + private string GetDriverWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var commandVar = Variable.Command.AsVarName(); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var returnLastId = ((IExecLastId)dbDriver).GetLastIdStatement(query).JoinByNewLine(); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var {{commandVar}} = this.{{transactionProperty}}.Connection.CreateCommand()) + { + {{commandVar}}.CommandText = {{sqlVar}}; + {{commandVar}}.Transaction = this.{{transactionProperty}}; + {{commandParameters}} + {{returnLastId}} + } + """; } } \ No newline at end of file diff --git a/Drivers/Generators/ExecRowsDeclareGen.cs b/Drivers/Generators/ExecRowsDeclareGen.cs index b8ca1952..ec6806f7 100644 --- a/Drivers/Generators/ExecRowsDeclareGen.cs +++ b/Drivers/Generators/ExecRowsDeclareGen.cs @@ -1,5 +1,6 @@ using Microsoft.CodeAnalysis.CSharp.Syntax; using Plugin; +using System.Linq; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace SqlcGenCsharp.Drivers.Generators; @@ -21,39 +22,92 @@ public MemberDeclarationSyntax Generate(string queryTextConstant, string argInte private string GetMethodBody(string queryTextConstant, Query query) { - var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); var sqlTextTransform = CommonGen.GetSqlTransformations(query, queryTextConstant); - return dbDriver.Options.UseDapper ? GetAsDapper() : GetAsDriver(); - - string GetAsDapper() - { - var dapperParamsSection = CommonGen.ConstructDapperParamsDict(query.Params); - var dapperArgs = dapperParamsSection != string.Empty ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; - return $$""" - using ({{establishConnection}}) - {{{sqlTextTransform}}{{dapperParamsSection}} - return await {{Variable.Connection.AsVarName()}}.ExecuteAsync({{queryTextConstant}}{{dapperArgs}}); - } - """; - } - - string GetAsDriver() - { - var createSqlCommand = dbDriver.CreateSqlCommand(sqlTextTransform != string.Empty - ? Variable.TransformedSql.AsVarName() - : queryTextConstant); - var commandParameters = CommonGen.AddParametersToCommand(query.Params); - return $$""" - using ({{establishConnection}}) - { - {{connectionOpen.AppendSemicolonUnlessEmpty()}}{{sqlTextTransform}} - using ({{createSqlCommand}}) - { + var useDapper = dbDriver.Options.UseDapper; + + var dapperParams = useDapper ? CommonGen.ConstructDapperParamsDict(query.Params) : string.Empty; + var sqlVar = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; + var transactionProperty = Variable.Transaction.AsPropertyName(); + + var noTxBody = useDapper ? GetDapperNoTxBody(sqlVar, query) : GetDriverNoTxBody(sqlVar, query); + var withTxBody = useDapper ? GetDapperWithTxBody(sqlVar, query) : GetDriverWithTxBody(sqlVar, query); + + return $$""" + {{sqlTextTransform}} + {{dapperParams}} + if (this.{{transactionProperty}} == null) + { + {{noTxBody}} + } + {{withTxBody}} + """; + } + + private string GetDapperNoTxBody(string sqlVar, Query query) + { + var (establishConnection, _) = dbDriver.EstablishConnection(query); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + using ({{establishConnection}}) + { + return await {{Variable.Connection.AsVarName()}}.ExecuteAsync({{sqlVar}}{{dapperArgs}}); + } + """; + } + + private string GetDapperWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.{{transactionProperty}}.Connection.ExecuteAsync( + {{sqlVar}}{{dapperArgs}}, + transaction: this.{{transactionProperty}}); + """; + } + + private string GetDriverNoTxBody(string sqlVar, Query query) + { + var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); + var createSqlCommand = dbDriver.CreateSqlCommand(sqlVar); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + return $$""" + using ({{establishConnection}}) + { + {{connectionOpen.AppendSemicolonUnlessEmpty()}} + using ({{createSqlCommand}}) + { {{commandParameters}} return await {{Variable.Command.AsVarName()}}.ExecuteNonQueryAsync(); - } - } - """; - } + } + } + """; + } + + private string GetDriverWithTxBody(string sqlVar, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var commandVar = Variable.Command.AsVarName(); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var {{commandVar}} = this.{{transactionProperty}}.Connection.CreateCommand()) + { + {{commandVar}}.CommandText = {{sqlVar}}; + {{commandVar}}.Transaction = this.{{transactionProperty}}; + {{commandParameters}} + return await {{commandVar}}.ExecuteNonQueryAsync(); + } + """; } } \ No newline at end of file diff --git a/Drivers/Generators/ManyDeclareGen.cs b/Drivers/Generators/ManyDeclareGen.cs index d7dba854..e9c77ee4 100644 --- a/Drivers/Generators/ManyDeclareGen.cs +++ b/Drivers/Generators/ManyDeclareGen.cs @@ -24,47 +24,81 @@ public MemberDeclarationSyntax Generate(string queryTextConstant, string argInte private string GetMethodBody(string queryTextConstant, string returnInterface, Query query) { - var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); var sqlTextTransform = CommonGen.GetSqlTransformations(query, queryTextConstant); - var resultVar = Variable.Result.AsVarName(); var anyEmbeddedTableExists = query.Columns.Any(c => c.EmbedTable is not null); - return dbDriver.Options.UseDapper && !anyEmbeddedTableExists - ? GetAsDapper() - : GetAsDriver(); - - string GetAsDapper() - { - var dapperParamsSection = CommonGen.ConstructDapperParamsDict(query.Params); - var dapperArgs = dapperParamsSection != string.Empty ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; - var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, true); - var sqlQuery = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; - - return $$""" - using ({{establishConnection}}) - {{{sqlTextTransform}}{{dapperParamsSection}} - var {{resultVar}} = await {{Variable.Connection.AsVarName()}}.QueryAsync<{{returnType}}>({{sqlQuery}}{{dapperArgs}}); - return {{resultVar}}.AsList(); - } - """; - } - - string GetAsDriver() - { - var createSqlCommand = dbDriver.CreateSqlCommand(sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant); - var commandParameters = CommonGen.AddParametersToCommand(query.Params); - var initDataReader = CommonGen.InitDataReader(); - var awaitReaderRow = CommonGen.AwaitReaderRow(); - var dataclassInit = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); - var readWhileExists = $$""" + var useDapper = dbDriver.Options.UseDapper && !anyEmbeddedTableExists; + + var dapperParams = useDapper ? CommonGen.ConstructDapperParamsDict(query.Params) : string.Empty; + var sqlVar = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; + var transactionProperty = Variable.Transaction.AsPropertyName(); + + var noTxBody = useDapper ? GetDapperNoTxBody(sqlVar, returnInterface, query) : GetDriverNoTxBody(sqlVar, returnInterface, query); + var withTxBody = useDapper ? GetDapperWithTxBody(sqlVar, returnInterface, query) : GetDriverWithTxBody(sqlVar, returnInterface, query); + + return $$""" + {{sqlTextTransform}} + {{dapperParams}} + if (this.{{transactionProperty}} == null) + { + {{noTxBody}} + } + {{withTxBody}} + """; + } + + private string GetDapperNoTxBody(string sqlVar, string returnInterface, Query query) + { + var (establishConnection, _) = dbDriver.EstablishConnection(query); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, true); + + return $$""" + using ({{establishConnection}}) + { + var {{Variable.Result.AsVarName()}} = await {{Variable.Connection.AsVarName()}}.QueryAsync<{{returnType}}>({{sqlVar}}{{dapperArgs}}); + return {{Variable.Result.AsVarName()}}.AsList(); + } + """; + } + + private string GetDapperWithTxBody(string sqlVar, string returnInterface, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, true); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return (await this.{{transactionProperty}}.Connection.QueryAsync<{{returnType}}>( + {{sqlVar}}{{dapperArgs}}, + transaction: this.{{transactionProperty}})).AsList(); + """; + } + + private string GetDriverNoTxBody(string sqlVar, string returnInterface, Query query) + { + var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); + var createSqlCommand = dbDriver.CreateSqlCommand(sqlVar); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var initDataReader = CommonGen.InitDataReader(); + var awaitReaderRow = CommonGen.AwaitReaderRow(); + var dataclassInit = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); + var resultVar = Variable.Result.AsVarName(); + var readWhileExists = $$""" while ({{awaitReaderRow}}) { {{resultVar}}.Add({{dataclassInit}}); } """; - return $$""" + // TODO: add return null at end of code run so transaction code will not run? + return $$""" using ({{establishConnection}}) { - {{connectionOpen.AppendSemicolonUnlessEmpty()}}{{sqlTextTransform}} + {{connectionOpen.AppendSemicolonUnlessEmpty()}} using ({{createSqlCommand}}) { {{commandParameters}} @@ -77,6 +111,42 @@ string GetAsDriver() } } """; - } + } + + private string GetDriverWithTxBody(string sqlVar, string returnInterface, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var commandVar = Variable.Command.AsVarName(); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var initDataReader = CommonGen.InitDataReader(); + var awaitReaderRow = CommonGen.AwaitReaderRow(); + var dataclassInit = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); + var resultVar = Variable.Result.AsVarName(); + var readWhileExists = $$""" + while ({{awaitReaderRow}}) + { + {{resultVar}}.Add({{dataclassInit}}); + } + """; + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var {{commandVar}} = this.{{transactionProperty}}.Connection.CreateCommand()) + { + {{commandVar}}.CommandText = {{sqlVar}}; + {{commandVar}}.Transaction = this.{{transactionProperty}}; + {{commandParameters}} + using ({{initDataReader}}) + { + var {{resultVar}} = new List<{{returnInterface}}>(); + {{readWhileExists}} + return {{resultVar}}; + } + } + """; } } \ No newline at end of file diff --git a/Drivers/Generators/OneDeclareGen.cs b/Drivers/Generators/OneDeclareGen.cs index 1156e7b1..cfaf99f7 100644 --- a/Drivers/Generators/OneDeclareGen.cs +++ b/Drivers/Generators/OneDeclareGen.cs @@ -24,55 +24,119 @@ public MemberDeclarationSyntax Generate(string queryTextConstant, string argInte private string GetMethodBody(string queryTextConstant, string returnInterface, Query query) { - var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); var sqlTextTransform = CommonGen.GetSqlTransformations(query, queryTextConstant); - var connectionVar = Variable.Connection.AsVarName(); - var resultVar = Variable.Result.AsVarName(); var anyEmbeddedTableExists = query.Columns.Any(c => c.EmbedTable is not null); - return dbDriver.Options.UseDapper && !anyEmbeddedTableExists - ? GetAsDapper() - : GetAsDriver(); - - string GetAsDapper() - { - var dapperParamsSection = CommonGen.ConstructDapperParamsDict(query.Params); - var dapperArgs = dapperParamsSection != string.Empty ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; - var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, false); - - return $$""" - using ({{establishConnection}}) - {{{sqlTextTransform}}{{dapperParamsSection}} - var {{resultVar}} = await {{connectionVar}}.QueryFirstOrDefaultAsync<{{returnType}}>({{queryTextConstant}}{{dapperArgs}}); - return {{resultVar}}; + var useDapper = dbDriver.Options.UseDapper && !anyEmbeddedTableExists; + + var dapperParams = useDapper ? CommonGen.ConstructDapperParamsDict(query.Params) : string.Empty; + var sqlVar = sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant; + var transactionProperty = Variable.Transaction.AsPropertyName(); + + var noTxBody = useDapper ? GetDapperNoTxBody(sqlVar, returnInterface, query) : GetDriverNoTxBody(sqlVar, returnInterface, query); + var withTxBody = useDapper ? GetDapperWithTxBody(sqlVar, returnInterface, query) : GetDriverWithTxBody(sqlVar, returnInterface, query); + + return $$""" + {{sqlTextTransform}} + {{dapperParams}} + if (this.{{transactionProperty}} == null) + { + {{noTxBody}} + } + {{withTxBody}} + """; + } + + private string GetDapperNoTxBody(string sqlVar, string returnInterface, Query query) + { + var (establishConnection, _) = dbDriver.EstablishConnection(query); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, false); + + return $$""" + using ({{establishConnection}}) + { + var {{Variable.Result.AsVarName()}} = await {{Variable.Connection.AsVarName()}}.QueryFirstOrDefaultAsync<{{returnType}}>({{sqlVar}}{{dapperArgs}}); + return {{Variable.Result.AsVarName()}}; + } + """; + } + + private string GetDapperWithTxBody(string sqlVar, string returnInterface, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var dapperArgs = query.Params.Any() ? $", {Variable.QueryParams.AsVarName()}" : string.Empty; + var returnType = dbDriver.AddNullableSuffixIfNeeded(returnInterface, false); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.{{transactionProperty}}.Connection.QueryFirstOrDefaultAsync<{{returnType}}>( + {{sqlVar}}{{dapperArgs}}, + transaction: this.{{transactionProperty}}); + """; + } + + private string GetDriverNoTxBody(string sqlVar, string returnInterface, Query query) + { + var (establishConnection, connectionOpen) = dbDriver.EstablishConnection(query); + var createSqlCommand = dbDriver.CreateSqlCommand(sqlVar); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var initDataReader = CommonGen.InitDataReader(); + var awaitReaderRow = CommonGen.AwaitReaderRow(); + var returnDataclass = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); + + return $$""" + using ({{establishConnection}}) + { + {{connectionOpen.AppendSemicolonUnlessEmpty()}} + using ({{createSqlCommand}}) + { + {{commandParameters}} + using ({{initDataReader}}) + { + if ({{awaitReaderRow}}) + { + return {{returnDataclass}}; + } + } + } + } + return null; + """; + } + + private string GetDriverWithTxBody(string sqlVar, string returnInterface, Query query) + { + var transactionProperty = Variable.Transaction.AsPropertyName(); + var commandVar = Variable.Command.AsVarName(); + var commandParameters = CommonGen.AddParametersToCommand(query.Params); + var initDataReader = CommonGen.InitDataReader(); + var awaitReaderRow = CommonGen.AwaitReaderRow(); + var returnDataclass = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); + + return $$""" + if (this.{{transactionProperty}}?.Connection == null || this.{{transactionProperty}}?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var {{commandVar}} = this.{{transactionProperty}}.Connection.CreateCommand()) + { + {{commandVar}}.CommandText = {{sqlVar}}; + {{commandVar}}.Transaction = this.{{transactionProperty}}; + {{commandParameters}} + using ({{initDataReader}}) + { + if ({{awaitReaderRow}}) + { + return {{returnDataclass}}; + } } - """; - } - - string GetAsDriver() - { - var createSqlCommand = dbDriver.CreateSqlCommand(sqlTextTransform != string.Empty ? Variable.TransformedSql.AsVarName() : queryTextConstant); - var commandParameters = CommonGen.AddParametersToCommand(query.Params); - var initDataReader = CommonGen.InitDataReader(); - var awaitReaderRow = CommonGen.AwaitReaderRow(); - var returnDataclass = CommonGen.InstantiateDataclass(query.Columns.ToArray(), returnInterface, query); - return $$""" - using ({{establishConnection}}) - { - {{connectionOpen.AppendSemicolonUnlessEmpty()}}{{sqlTextTransform}} - using ({{createSqlCommand}}) - { - {{commandParameters}} - using ({{initDataReader}}) - { - if ({{awaitReaderRow}}) - { - return {{returnDataclass}}; - } - } - } - } - return null; - """; - } + } + return null; + """; } } \ No newline at end of file diff --git a/Drivers/MySqlConnectorDriver.cs b/Drivers/MySqlConnectorDriver.cs index f28877c2..a9f51c45 100644 --- a/Drivers/MySqlConnectorDriver.cs +++ b/Drivers/MySqlConnectorDriver.cs @@ -123,6 +123,8 @@ public partial class MySqlConnectorDriver( ) }; + public override string TransactionClassName => "MySqlTransaction"; + public override UsingDirectiveSyntax[] GetUsingDirectivesForQueries() { return base.GetUsingDirectivesForQueries() diff --git a/Drivers/NpgsqlDriver.cs b/Drivers/NpgsqlDriver.cs index ca1da3c0..461a27ca 100644 --- a/Drivers/NpgsqlDriver.cs +++ b/Drivers/NpgsqlDriver.cs @@ -198,6 +198,8 @@ public NpgsqlDriver( ) }; + public override string TransactionClassName => "NpgsqlTransaction"; + public override UsingDirectiveSyntax[] GetUsingDirectivesForQueries() { return base.GetUsingDirectivesForQueries() @@ -243,6 +245,13 @@ public override string[] GetConstructorStatements() .ToArray(); } + public override string[] GetTransactionConstructorStatements() + { + return base.GetTransactionConstructorStatements() + .AppendIf("Utils.ConfigureSqlMapper();", Options.UseDapper) + .ToArray(); + } + public override MemberDeclarationSyntax[] GetMemberDeclarationsForUtils() { var memberDeclarations = base.GetMemberDeclarationsForUtils(); diff --git a/Drivers/SqliteDriver.cs b/Drivers/SqliteDriver.cs index adb0cc56..65dd7f21 100644 --- a/Drivers/SqliteDriver.cs +++ b/Drivers/SqliteDriver.cs @@ -64,6 +64,8 @@ public partial class SqliteDriver( ), }; + public override string TransactionClassName => "SqliteTransaction"; + public override UsingDirectiveSyntax[] GetUsingDirectivesForQueries() { return base.GetUsingDirectivesForQueries() diff --git a/Drivers/Variable.cs b/Drivers/Variable.cs index 2d51d43e..1fbcc8ab 100644 --- a/Drivers/Variable.cs +++ b/Drivers/Variable.cs @@ -5,6 +5,7 @@ public enum Variable Options, Config, ConnectionString, + Transaction, Connection, Command, diff --git a/docs/03_Usage.md b/docs/03_Usage.md index 72abc15f..0df33541 100644 --- a/docs/03_Usage.md +++ b/docs/03_Usage.md @@ -62,3 +62,46 @@ More info can be found in [here](https://docs.sqlc.dev/en/stable/reference/query | sqlc.embed | ✅ | ✅ | ✅ | More info can be found in [here](https://docs.sqlc.dev/en/stable/reference/macros.html#macros). + + +### Transactions +Transactions are supported by the plugin. +
+ +#### Example using a transaction +```C# +public async Task ExampleTransaction(IDbConnection connection) +{ + // Begin a transaction + using (var transaction = connection.BeginTransaction()) + { + try + { + // Create a new Queries object with the transaction instead of the connection + var queries = QuerySql.WithTransaction(transaction); + + // Example: Insert a new author + var newAuthor = await queries.CreateAuthor(new CreateAuthorParams { Name = "Jane Doe", Bio = "Another author" }); + + // Example: Get the author by ID within the same transaction + var author = await queries.GetAuthor(newAuthor.AuthorID); + + // Example: Update the author's bio + await queries.UpdateAuthorBio(new UpdateAuthorBioParams { AuthorID = author.AuthorID, Bio = "Updated bio for Jane Doe" }); + + // Commit the transaction if all operations are successful + transaction.Commit(); + Console.WriteLine("Transaction committed successfully."); + } + catch (Exception ex) + { + // Rollback the transaction if any error occurs + transaction.Rollback(); + Console.WriteLine($"Transaction rolled back due to error: {ex.Message}"); + throw; + } + } +} +``` + +More info can be found in [here](https://docs.sqlc.dev/en/stable/howto/transactions.html). \ No newline at end of file diff --git a/end2end/EndToEndScaffold/Config.cs b/end2end/EndToEndScaffold/Config.cs index 6f6fc214..77f4b52f 100644 --- a/end2end/EndToEndScaffold/Config.cs +++ b/end2end/EndToEndScaffold/Config.cs @@ -30,6 +30,8 @@ public enum KnownTestType SqliteDataTypes, SqliteDataTypesOverride, SqliteCopyFrom, + SqliteTransaction, + SqliteTransactionRollback, // Postgres PostgresStringDataTypes, @@ -40,6 +42,8 @@ public enum KnownTestType PostgresDataTypesOverride, PostgresStringCopyFrom, + PostgresTransaction, + PostgresTransactionRollback, PostgresIntegerCopyFrom, PostgresFloatingPointCopyFrom, PostgresDateTimeCopyFrom, @@ -52,6 +56,8 @@ public enum KnownTestType // MySql MySqlStringDataTypes, MySqlIntegerDataTypes, + MySqlTransaction, + MySqlTransactionRollback, MySqlFloatingPointDataTypes, MySqlDateTimeDataTypes, MySqlBinaryDataTypes, @@ -92,6 +98,8 @@ internal static class Config KnownTestType.MySqlStringDataTypes, KnownTestType.MySqlIntegerDataTypes, + KnownTestType.MySqlTransaction, + KnownTestType.MySqlTransactionRollback, KnownTestType.MySqlFloatingPointDataTypes, KnownTestType.MySqlDateTimeDataTypes, KnownTestType.MySqlBinaryDataTypes, @@ -128,6 +136,8 @@ internal static class Config KnownTestType.MySqlStringDataTypes, KnownTestType.MySqlIntegerDataTypes, + KnownTestType.MySqlTransaction, + KnownTestType.MySqlTransactionRollback, KnownTestType.MySqlFloatingPointDataTypes, KnownTestType.MySqlDateTimeDataTypes, KnownTestType.MySqlBinaryDataTypes, @@ -162,6 +172,8 @@ internal static class Config KnownTestType.NargNull, KnownTestType.NargNotNull, + KnownTestType.PostgresTransaction, + KnownTestType.PostgresTransactionRollback, KnownTestType.PostgresStringDataTypes, KnownTestType.PostgresIntegerDataTypes, KnownTestType.PostgresFloatingPointDataTypes, @@ -195,6 +207,8 @@ internal static class Config KnownTestType.MultipleArraysAsParams, KnownTestType.NargNull, KnownTestType.NargNotNull, + KnownTestType.PostgresTransaction, + KnownTestType.PostgresTransactionRollback, KnownTestType.PostgresStringDataTypes, KnownTestType.PostgresIntegerDataTypes, @@ -229,6 +243,8 @@ internal static class Config KnownTestType.MultipleSlices, KnownTestType.NargNull, KnownTestType.NargNotNull, + KnownTestType.SqliteTransaction, + KnownTestType.SqliteTransactionRollback, KnownTestType.SqliteDataTypes, KnownTestType.SqliteCopyFrom, KnownTestType.SqliteDataTypesOverride @@ -252,6 +268,8 @@ internal static class Config KnownTestType.MultipleSlices, KnownTestType.NargNull, KnownTestType.NargNotNull, + KnownTestType.SqliteTransaction, + KnownTestType.SqliteTransactionRollback, KnownTestType.SqliteDataTypes, KnownTestType.SqliteCopyFrom, KnownTestType.SqliteDataTypesOverride diff --git a/end2end/EndToEndScaffold/Templates/MySqlTests.cs b/end2end/EndToEndScaffold/Templates/MySqlTests.cs index 99b0e400..01f76de8 100644 --- a/end2end/EndToEndScaffold/Templates/MySqlTests.cs +++ b/end2end/EndToEndScaffold/Templates/MySqlTests.cs @@ -523,6 +523,55 @@ public async Task TestBinaryCopyFrom( } """ }, + [KnownTestType.MySqlTransaction] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestMySqlTransaction() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + + await transaction.CommitAsync(); + + var expected = new QuerySql.GetAuthorRow + { + Id = {{Consts.BojackId}}, + Name = {{Consts.BojackAuthor}}, + Bio = {{Consts.BojackTheme}} + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(SingularEquals(expected, actual{{Consts.UnknownRecordValuePlaceholder}})); // Apply placeholder here + } + """ + }, + [KnownTestType.MySqlTransactionRollback] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestMySqlTransactionRollback() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + await transaction.RollbackAsync(); + + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actual == null, "author should not exist after rollback"); + } + """ + }, [KnownTestType.MySqlEnumCopyFrom] = new TestImpl { Impl = $$""" diff --git a/end2end/EndToEndScaffold/Templates/PostgresTests.cs b/end2end/EndToEndScaffold/Templates/PostgresTests.cs index 1d93d048..8a0b04e7 100644 --- a/end2end/EndToEndScaffold/Templates/PostgresTests.cs +++ b/end2end/EndToEndScaffold/Templates/PostgresTests.cs @@ -484,6 +484,56 @@ public async Task TestPostgresGeoTypes(NpgsqlPoint? cPoint, NpgsqlLine? cLine, N } """ }, + [KnownTestType.PostgresTransaction] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestPostgresTransaction() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + // The GetAuthor method in NpgsqlExampleGen returns QuerySql.GetAuthorRow? (nullable record struct) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + + await transaction.CommitAsync(); + + var expected = new QuerySql.GetAuthorRow + { + Id = {{Consts.BojackId}}, + Name = {{Consts.BojackAuthor}}, + Bio = {{Consts.BojackTheme}} + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(SingularEquals(expected, actual{{Consts.UnknownRecordValuePlaceholder}})); // Apply placeholder here + } + """ + }, + [KnownTestType.PostgresTransactionRollback] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestPostgresTransactionRollback() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + await transaction.RollbackAsync(); + + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actual == null, "author should not exist after rollback"); + } + """ + }, [KnownTestType.PostgresDataTypesOverride] = new TestImpl { Impl = $$""" diff --git a/end2end/EndToEndScaffold/Templates/SqliteTests.cs b/end2end/EndToEndScaffold/Templates/SqliteTests.cs index 6a20b829..03f6f8c0 100644 --- a/end2end/EndToEndScaffold/Templates/SqliteTests.cs +++ b/end2end/EndToEndScaffold/Templates/SqliteTests.cs @@ -89,6 +89,56 @@ private static void AssertSingularEquals(QuerySql.GetSqliteTypesCntRow expected, } """ }, + [KnownTestType.SqliteTransaction] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestSqliteTransaction() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + // The GetAuthor method in SqliteExampleGen returns QuerySql.GetAuthorRow? (nullable record struct/class) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + + transaction.Commit(); + + var expected = new QuerySql.GetAuthorRow + { + Id = {{Consts.BojackId}}, + Name = {{Consts.BojackAuthor}}, + Bio = {{Consts.BojackTheme}} + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(SingularEquals(expected, actual{{Consts.UnknownRecordValuePlaceholder}})); // Apply placeholder here + } + """ + }, + [KnownTestType.SqliteTransactionRollback] = new TestImpl + { + Impl = $$""" + [Test] + public async Task TestSqliteTransactionRollback() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = {{Consts.BojackId}}, Name = {{Consts.BojackAuthor}}, Bio = {{Consts.BojackTheme}} }); + + transaction.Rollback(); + + var actual = await this.QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = {{Consts.BojackAuthor}} }); + Assert.That(actual == null, "author should not exist after rollback"); + } + """ + }, [KnownTestType.SqliteDataTypesOverride] = new TestImpl { Impl = $$""" diff --git a/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs b/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs index f195ae6c..7d3a55a0 100644 --- a/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs +++ b/end2end/EndToEndTests/MySqlConnectorDapperTester.generated.cs @@ -361,6 +361,40 @@ public async Task TestMySqlIntegerTypes(bool? cBool, bool? cBoolean, short? cTin Assert.That(actual.CBigint, Is.EqualTo(expected.CBigint)); } + [Test] + public async Task TestMySqlTransaction() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestMySqlTransactionRollback() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(3.4f, -31.555666, 11.098643, 34.4424, 423.2445, 998.9994542, 21.214312452534)] [TestCase(null, null, null, null, null, null, null)] diff --git a/end2end/EndToEndTests/MySqlConnectorTester.generated.cs b/end2end/EndToEndTests/MySqlConnectorTester.generated.cs index b9747a47..df9a4c6d 100644 --- a/end2end/EndToEndTests/MySqlConnectorTester.generated.cs +++ b/end2end/EndToEndTests/MySqlConnectorTester.generated.cs @@ -361,6 +361,40 @@ public async Task TestMySqlIntegerTypes(bool? cBool, bool? cBoolean, short? cTin Assert.That(actual.Value.CBigint, Is.EqualTo(expected.CBigint)); } + [Test] + public async Task TestMySqlTransaction() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual.Value)); // Apply placeholder here + } + + [Test] + public async Task TestMySqlTransactionRollback() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(3.4f, -31.555666, 11.098643, 34.4424, 423.2445, 998.9994542, 21.214312452534)] [TestCase(null, null, null, null, null, null, null)] diff --git a/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs b/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs index 28188d5a..636a4606 100644 --- a/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs +++ b/end2end/EndToEndTests/NpgsqlDapperTester.generated.cs @@ -435,6 +435,41 @@ public async Task TestStringCopyFrom(int batchSize, string cChar, string cVarcha Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + [Test] + public async Task TestPostgresTransaction() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in NpgsqlExampleGen returns QuerySql.GetAuthorRow? (nullable record struct) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestPostgresTransactionRollback() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(100, true, 3, 453, -1445214231L)] [TestCase(10, null, null, null, null)] diff --git a/end2end/EndToEndTests/NpgsqlTester.generated.cs b/end2end/EndToEndTests/NpgsqlTester.generated.cs index b70f16d8..1facb2b7 100644 --- a/end2end/EndToEndTests/NpgsqlTester.generated.cs +++ b/end2end/EndToEndTests/NpgsqlTester.generated.cs @@ -435,6 +435,41 @@ public async Task TestStringCopyFrom(int batchSize, string cChar, string cVarcha Assert.That(actual.Value.CText, Is.EqualTo(expected.CText)); } + [Test] + public async Task TestPostgresTransaction() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in NpgsqlExampleGen returns QuerySql.GetAuthorRow? (nullable record struct) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual.Value)); // Apply placeholder here + } + + [Test] + public async Task TestPostgresTransactionRollback() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(100, true, 3, 453, -1445214231L)] [TestCase(10, null, null, null, null)] diff --git a/end2end/EndToEndTests/SqliteDapperTester.generated.cs b/end2end/EndToEndTests/SqliteDapperTester.generated.cs index c6e3a3bd..64a4dee5 100644 --- a/end2end/EndToEndTests/SqliteDapperTester.generated.cs +++ b/end2end/EndToEndTests/SqliteDapperTester.generated.cs @@ -380,5 +380,40 @@ private static void AssertSingularEquals(QuerySql.GetSqliteTypesCntRow expected, Assert.That(actual.CReal, Is.EqualTo(expected.CReal)); Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + + [Test] + public async Task TestSqliteTransaction() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in SqliteExampleGen returns QuerySql.GetAuthorRow? (nullable record struct/class) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + transaction.Commit(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestSqliteTransactionRollback() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + transaction.Rollback(); + var actual = await this.QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } } } diff --git a/end2end/EndToEndTests/SqliteTester.generated.cs b/end2end/EndToEndTests/SqliteTester.generated.cs index d0fedd23..e4c7aad5 100644 --- a/end2end/EndToEndTests/SqliteTester.generated.cs +++ b/end2end/EndToEndTests/SqliteTester.generated.cs @@ -380,5 +380,40 @@ private static void AssertSingularEquals(QuerySql.GetSqliteTypesCntRow expected, Assert.That(actual.CReal, Is.EqualTo(expected.CReal)); Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + + [Test] + public async Task TestSqliteTransaction() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in SqliteExampleGen returns QuerySql.GetAuthorRow? (nullable record struct/class) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + transaction.Commit(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual.Value)); // Apply placeholder here + } + + [Test] + public async Task TestSqliteTransactionRollback() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + transaction.Rollback(); + var actual = await this.QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } } } diff --git a/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs index ca83b51e..98e738b9 100644 --- a/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/MySqlConnectorDapperTester.generated.cs @@ -361,6 +361,40 @@ public async Task TestMySqlIntegerTypes(bool? cBool, bool? cBoolean, short? cTin Assert.That(actual.CBigint, Is.EqualTo(expected.CBigint)); } + [Test] + public async Task TestMySqlTransaction() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestMySqlTransactionRollback() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(3.4f, -31.555666, 11.098643, 34.4424, 423.2445, 998.9994542, 21.214312452534)] [TestCase(null, null, null, null, null, null, null)] diff --git a/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs b/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs index 8b34b643..8085b93a 100644 --- a/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/MySqlConnectorTester.generated.cs @@ -361,6 +361,40 @@ public async Task TestMySqlIntegerTypes(bool? cBool, bool? cBoolean, short? cTin Assert.That(actual.CBigint, Is.EqualTo(expected.CBigint)); } + [Test] + public async Task TestMySqlTransaction() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestMySqlTransactionRollback() + { + var connection = new MySqlConnector.MySqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.MySqlConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(3.4f, -31.555666, 11.098643, 34.4424, 423.2445, 998.9994542, 21.214312452534)] [TestCase(null, null, null, null, null, null, null)] diff --git a/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs index 0e312af0..79ed9b8b 100644 --- a/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/NpgsqlDapperTester.generated.cs @@ -435,6 +435,41 @@ public async Task TestStringCopyFrom(int batchSize, string cChar, string cVarcha Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + [Test] + public async Task TestPostgresTransaction() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in NpgsqlExampleGen returns QuerySql.GetAuthorRow? (nullable record struct) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestPostgresTransactionRollback() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(100, true, 3, 453, -1445214231L)] [TestCase(10, null, null, null, null)] diff --git a/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs b/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs index 1e26d580..df9725f6 100644 --- a/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/NpgsqlTester.generated.cs @@ -435,6 +435,41 @@ public async Task TestStringCopyFrom(int batchSize, string cChar, string cVarcha Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + [Test] + public async Task TestPostgresTransaction() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in NpgsqlExampleGen returns QuerySql.GetAuthorRow? (nullable record struct) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + await transaction.CommitAsync(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestPostgresTransactionRollback() + { + var connection = new Npgsql.NpgsqlConnection(Environment.GetEnvironmentVariable(EndToEndCommon.PostgresConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + await transaction.RollbackAsync(); + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } + [Test] [TestCase(100, true, 3, 453, -1445214231L)] [TestCase(10, null, null, null, null)] diff --git a/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs b/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs index d83f2692..64ef7e14 100644 --- a/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/SqliteDapperTester.generated.cs @@ -380,5 +380,40 @@ private static void AssertSingularEquals(QuerySql.GetSqliteTypesCntRow expected, Assert.That(actual.CReal, Is.EqualTo(expected.CReal)); Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + + [Test] + public async Task TestSqliteTransaction() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in SqliteExampleGen returns QuerySql.GetAuthorRow? (nullable record struct/class) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + transaction.Commit(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestSqliteTransactionRollback() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + transaction.Rollback(); + var actual = await this.QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } } } diff --git a/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs b/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs index 77d7dae6..5ca0cf9f 100644 --- a/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs +++ b/end2end/EndToEndTestsLegacy/SqliteTester.generated.cs @@ -380,5 +380,40 @@ private static void AssertSingularEquals(QuerySql.GetSqliteTypesCntRow expected, Assert.That(actual.CReal, Is.EqualTo(expected.CReal)); Assert.That(actual.CText, Is.EqualTo(expected.CText)); } + + [Test] + public async Task TestSqliteTransaction() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var querySqlWithTx = QuerySql.WithTransaction(transaction); + await querySqlWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + // The GetAuthor method in SqliteExampleGen returns QuerySql.GetAuthorRow? (nullable record struct/class) + var actualNull = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actualNull == null, "there is author"); // This is correct for nullable types + transaction.Commit(); + var expected = new QuerySql.GetAuthorRow + { + Id = 1111, + Name = "Bojack Horseman", + Bio = "Back in the 90s he was in a very famous TV show" + }; + var actual = await QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(SingularEquals(expected, actual)); // Apply placeholder here + } + + [Test] + public async Task TestSqliteTransactionRollback() + { + var connection = new Microsoft.Data.Sqlite.SqliteConnection(Environment.GetEnvironmentVariable(EndToEndCommon.SqliteConnectionStringEnv)); + await connection.OpenAsync(); + var transaction = connection.BeginTransaction(); + var sqlQueryWithTx = QuerySql.WithTransaction(transaction); + await sqlQueryWithTx.CreateAuthor(new QuerySql.CreateAuthorArgs { Id = 1111, Name = "Bojack Horseman", Bio = "Back in the 90s he was in a very famous TV show" }); + transaction.Rollback(); + var actual = await this.QuerySql.GetAuthor(new QuerySql.GetAuthorArgs { Name = "Bojack Horseman" }); + Assert.That(actual == null, "author should not exist after rollback"); + } } } diff --git a/examples/MySqlConnectorDapperExample/QuerySql.cs b/examples/MySqlConnectorDapperExample/QuerySql.cs index fe20c9f0..de07ffba 100644 --- a/examples/MySqlConnectorDapperExample/QuerySql.cs +++ b/examples/MySqlConnectorDapperExample/QuerySql.cs @@ -25,7 +25,19 @@ public QuerySql(string connectionString) Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; } - private string ConnectionString { get; } + private QuerySql(MySqlTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + } + + public static QuerySql WithTransaction(MySqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private MySqlTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1; SELECT LAST_INSERT_ID()"; public class GetAuthorRow @@ -40,13 +52,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name ; SELECT LAST_INSERT_ID ( ) "; @@ -58,11 +80,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio); SELECT LAST_INSERT_ID()"; @@ -74,14 +106,26 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - await connection.ExecuteAsync(CreateAuthorSql, queryParams); + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio); SELECT LAST_INSERT_ID()"; @@ -92,13 +136,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1; SELECT LAST_INSERT_ID()"; @@ -114,13 +168,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) ; SELECT LAST_INSERT_ID ( ) "; @@ -136,13 +200,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name ; SELECT LAST_INSERT_ID ( ) "; @@ -152,21 +226,45 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string DeleteAllAuthorsSql = "DELETE FROM authors; SELECT LAST_INSERT_ID()"; public async Task DeleteAllAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllAuthorsSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(DeleteAllAuthorsSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL ; SELECT LAST_INSERT_ID ( ) "; @@ -176,12 +274,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids); SELECT LAST_INSERT_ID()"; @@ -197,16 +305,26 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names); SELECT LAST_INSERT_ID()"; @@ -223,19 +341,29 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + queryParams.Add($"@namesArg{i}", args.Names[i]); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - queryParams.Add($"@namesArg{i}", args.Names[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id); SELECT LAST_INSERT_ID()"; @@ -246,13 +374,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name ; SELECT LAST_INSERT_ID ( ) "; @@ -263,21 +401,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -290,21 +452,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -323,22 +509,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -384,46 +595,58 @@ public class InsertMysqlTypesArgs }; public async Task InsertMysqlTypes(InsertMysqlTypesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_bit", args.CBit); + queryParams.Add("c_bool", args.CBool); + queryParams.Add("c_boolean", args.CBoolean); + queryParams.Add("c_tinyint", args.CTinyint); + queryParams.Add("c_smallint", args.CSmallint); + queryParams.Add("c_mediumint", args.CMediumint); + queryParams.Add("c_int", args.CInt); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_bigint", args.CBigint); + queryParams.Add("c_decimal", args.CDecimal); + queryParams.Add("c_dec", args.CDec); + queryParams.Add("c_numeric", args.CNumeric); + queryParams.Add("c_fixed", args.CFixed); + queryParams.Add("c_float", args.CFloat); + queryParams.Add("c_double", args.CDouble); + queryParams.Add("c_double_precision", args.CDoublePrecision); + queryParams.Add("c_char", args.CChar); + queryParams.Add("c_nchar", args.CNchar); + queryParams.Add("c_national_char", args.CNationalChar); + queryParams.Add("c_varchar", args.CVarchar); + queryParams.Add("c_tinytext", args.CTinytext); + queryParams.Add("c_mediumtext", args.CMediumtext); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_longtext", args.CLongtext); + queryParams.Add("c_enum", args.CEnum); + queryParams.Add("c_year", args.CYear); + queryParams.Add("c_date", args.CDate); + queryParams.Add("c_datetime", args.CDatetime); + queryParams.Add("c_timestamp", args.CTimestamp); + queryParams.Add("c_binary", args.CBinary); + queryParams.Add("c_varbinary", args.CVarbinary); + queryParams.Add("c_tinyblob", args.CTinyblob); + queryParams.Add("c_blob", args.CBlob); + queryParams.Add("c_mediumblob", args.CMediumblob); + queryParams.Add("c_longblob", args.CLongblob); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertMysqlTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("c_bit", args.CBit); - queryParams.Add("c_bool", args.CBool); - queryParams.Add("c_boolean", args.CBoolean); - queryParams.Add("c_tinyint", args.CTinyint); - queryParams.Add("c_smallint", args.CSmallint); - queryParams.Add("c_mediumint", args.CMediumint); - queryParams.Add("c_int", args.CInt); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_bigint", args.CBigint); - queryParams.Add("c_decimal", args.CDecimal); - queryParams.Add("c_dec", args.CDec); - queryParams.Add("c_numeric", args.CNumeric); - queryParams.Add("c_fixed", args.CFixed); - queryParams.Add("c_float", args.CFloat); - queryParams.Add("c_double", args.CDouble); - queryParams.Add("c_double_precision", args.CDoublePrecision); - queryParams.Add("c_char", args.CChar); - queryParams.Add("c_nchar", args.CNchar); - queryParams.Add("c_national_char", args.CNationalChar); - queryParams.Add("c_varchar", args.CVarchar); - queryParams.Add("c_tinytext", args.CTinytext); - queryParams.Add("c_mediumtext", args.CMediumtext); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_longtext", args.CLongtext); - queryParams.Add("c_enum", args.CEnum); - queryParams.Add("c_year", args.CYear); - queryParams.Add("c_date", args.CDate); - queryParams.Add("c_datetime", args.CDatetime); - queryParams.Add("c_timestamp", args.CTimestamp); - queryParams.Add("c_binary", args.CBinary); - queryParams.Add("c_varbinary", args.CVarbinary); - queryParams.Add("c_tinyblob", args.CTinyblob); - queryParams.Add("c_blob", args.CBlob); - queryParams.Add("c_mediumblob", args.CMediumblob); - queryParams.Add("c_longblob", args.CLongblob); - await connection.ExecuteAsync(InsertMysqlTypesSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertMysqlTypesSql, queryParams, transaction: this.Transaction); } public class InsertMysqlTypesBatchArgs @@ -567,11 +790,21 @@ public class GetMysqlTypesRow }; public async Task GetMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql, transaction: this.Transaction); } private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 ; SELECT LAST_INSERT_ID ( ) "; @@ -616,11 +849,21 @@ public class GetMysqlTypesCntRow }; public async Task GetMysqlTypesCnt() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql, transaction: this.Transaction); } private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp, max(c_bigint) as max_bigint FROM mysql_types ; SELECT LAST_INSERT_ID ( ) "; @@ -633,20 +876,42 @@ public class GetMysqlFunctionsRow }; public async Task GetMysqlFunctions() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql, transaction: this.Transaction); } private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types; SELECT LAST_INSERT_ID()"; public async Task TruncateMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateMysqlTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncateMysqlTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncateMysqlTypesSql, transaction: this.Transaction); } private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type); SELECT LAST_INSERT_ID()"; @@ -658,14 +923,26 @@ public class CreateExtendedBioArgs }; public async Task CreateExtendedBio(CreateExtendedBioArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("author_name", args.AuthorName); + queryParams.Add("name", args.Name); + queryParams.Add("bio_type", args.BioType); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateExtendedBioSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("author_name", args.AuthorName); - queryParams.Add("name", args.Name); - queryParams.Add("bio_type", args.BioType); - await connection.ExecuteAsync(CreateExtendedBioSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(CreateExtendedBioSql, queryParams, transaction: this.Transaction); } private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1; SELECT LAST_INSERT_ID()"; @@ -681,21 +958,43 @@ public class GetFirstExtendedBioByTypeArgs }; public async Task GetFirstExtendedBioByType(GetFirstExtendedBioByTypeArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio_type", args.BioType); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("bio_type", args.BioType); - var result = await connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams, transaction: this.Transaction); } private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios; SELECT LAST_INSERT_ID()"; public async Task TruncateExtendedBios() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateExtendedBiosSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncateExtendedBiosSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncateExtendedBiosSql, transaction: this.Transaction); } } \ No newline at end of file diff --git a/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs b/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs index 5165c5af..70a6f361 100644 --- a/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs +++ b/examples/MySqlConnectorDapperLegacyExample/QuerySql.cs @@ -26,6 +26,18 @@ public QuerySql(string connectionString) Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; } + private QuerySql(MySqlTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + } + + public static QuerySql WithTransaction(MySqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private MySqlTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1; SELECT LAST_INSERT_ID()"; @@ -41,13 +53,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name ; SELECT LAST_INSERT_ID ( ) "; @@ -59,11 +81,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio); SELECT LAST_INSERT_ID()"; @@ -75,14 +107,26 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - await connection.ExecuteAsync(CreateAuthorSql, queryParams); + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio); SELECT LAST_INSERT_ID()"; @@ -93,13 +137,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1; SELECT LAST_INSERT_ID()"; @@ -115,13 +169,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) ; SELECT LAST_INSERT_ID ( ) "; @@ -137,13 +201,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name ; SELECT LAST_INSERT_ID ( ) "; @@ -153,21 +227,45 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string DeleteAllAuthorsSql = "DELETE FROM authors; SELECT LAST_INSERT_ID()"; public async Task DeleteAllAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllAuthorsSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(DeleteAllAuthorsSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL ; SELECT LAST_INSERT_ID ( ) "; @@ -177,12 +275,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids); SELECT LAST_INSERT_ID()"; @@ -198,16 +306,26 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names); SELECT LAST_INSERT_ID()"; @@ -224,19 +342,29 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + queryParams.Add($"@namesArg{i}", args.Names[i]); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - queryParams.Add($"@namesArg{i}", args.Names[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id); SELECT LAST_INSERT_ID()"; @@ -247,13 +375,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name ; SELECT LAST_INSERT_ID ( ) "; @@ -264,21 +402,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -291,21 +453,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -324,22 +510,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -385,46 +596,58 @@ public class InsertMysqlTypesArgs }; public async Task InsertMysqlTypes(InsertMysqlTypesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_bit", args.CBit); + queryParams.Add("c_bool", args.CBool); + queryParams.Add("c_boolean", args.CBoolean); + queryParams.Add("c_tinyint", args.CTinyint); + queryParams.Add("c_smallint", args.CSmallint); + queryParams.Add("c_mediumint", args.CMediumint); + queryParams.Add("c_int", args.CInt); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_bigint", args.CBigint); + queryParams.Add("c_decimal", args.CDecimal); + queryParams.Add("c_dec", args.CDec); + queryParams.Add("c_numeric", args.CNumeric); + queryParams.Add("c_fixed", args.CFixed); + queryParams.Add("c_float", args.CFloat); + queryParams.Add("c_double", args.CDouble); + queryParams.Add("c_double_precision", args.CDoublePrecision); + queryParams.Add("c_char", args.CChar); + queryParams.Add("c_nchar", args.CNchar); + queryParams.Add("c_national_char", args.CNationalChar); + queryParams.Add("c_varchar", args.CVarchar); + queryParams.Add("c_tinytext", args.CTinytext); + queryParams.Add("c_mediumtext", args.CMediumtext); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_longtext", args.CLongtext); + queryParams.Add("c_enum", args.CEnum); + queryParams.Add("c_year", args.CYear); + queryParams.Add("c_date", args.CDate); + queryParams.Add("c_datetime", args.CDatetime); + queryParams.Add("c_timestamp", args.CTimestamp); + queryParams.Add("c_binary", args.CBinary); + queryParams.Add("c_varbinary", args.CVarbinary); + queryParams.Add("c_tinyblob", args.CTinyblob); + queryParams.Add("c_blob", args.CBlob); + queryParams.Add("c_mediumblob", args.CMediumblob); + queryParams.Add("c_longblob", args.CLongblob); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertMysqlTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("c_bit", args.CBit); - queryParams.Add("c_bool", args.CBool); - queryParams.Add("c_boolean", args.CBoolean); - queryParams.Add("c_tinyint", args.CTinyint); - queryParams.Add("c_smallint", args.CSmallint); - queryParams.Add("c_mediumint", args.CMediumint); - queryParams.Add("c_int", args.CInt); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_bigint", args.CBigint); - queryParams.Add("c_decimal", args.CDecimal); - queryParams.Add("c_dec", args.CDec); - queryParams.Add("c_numeric", args.CNumeric); - queryParams.Add("c_fixed", args.CFixed); - queryParams.Add("c_float", args.CFloat); - queryParams.Add("c_double", args.CDouble); - queryParams.Add("c_double_precision", args.CDoublePrecision); - queryParams.Add("c_char", args.CChar); - queryParams.Add("c_nchar", args.CNchar); - queryParams.Add("c_national_char", args.CNationalChar); - queryParams.Add("c_varchar", args.CVarchar); - queryParams.Add("c_tinytext", args.CTinytext); - queryParams.Add("c_mediumtext", args.CMediumtext); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_longtext", args.CLongtext); - queryParams.Add("c_enum", args.CEnum); - queryParams.Add("c_year", args.CYear); - queryParams.Add("c_date", args.CDate); - queryParams.Add("c_datetime", args.CDatetime); - queryParams.Add("c_timestamp", args.CTimestamp); - queryParams.Add("c_binary", args.CBinary); - queryParams.Add("c_varbinary", args.CVarbinary); - queryParams.Add("c_tinyblob", args.CTinyblob); - queryParams.Add("c_blob", args.CBlob); - queryParams.Add("c_mediumblob", args.CMediumblob); - queryParams.Add("c_longblob", args.CLongblob); - await connection.ExecuteAsync(InsertMysqlTypesSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertMysqlTypesSql, queryParams, transaction: this.Transaction); } public class InsertMysqlTypesBatchArgs @@ -567,11 +790,21 @@ public class GetMysqlTypesRow }; public async Task GetMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesSql, transaction: this.Transaction); } private const string GetMysqlTypesCntSql = "SELECT COUNT(1) AS cnt, c_bool, c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float , c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob FROM mysql_types GROUP BY c_bool , c_boolean, c_bit, c_tinyint, c_smallint, c_mediumint, c_int, c_integer, c_bigint, c_float, c_numeric, c_decimal, c_dec, c_fixed, c_double, c_double_precision, c_char, c_nchar, c_national_char, c_varchar, c_tinytext, c_mediumtext, c_text, c_longtext, c_enum, c_year, c_date, c_datetime, c_timestamp, c_binary, c_varbinary, c_tinyblob, c_blob, c_mediumblob, c_longblob LIMIT 1 ; SELECT LAST_INSERT_ID ( ) "; @@ -616,11 +849,21 @@ public class GetMysqlTypesCntRow }; public async Task GetMysqlTypesCnt() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlTypesCntSql, transaction: this.Transaction); } private const string GetMysqlFunctionsSql = "SELECT MAX(c_int) AS max_int, MAX(c_varchar) AS max_varchar, MAX(c_timestamp) AS max_timestamp, max(c_bigint) as max_bigint FROM mysql_types ; SELECT LAST_INSERT_ID ( ) "; @@ -633,20 +876,42 @@ public class GetMysqlFunctionsRow }; public async Task GetMysqlFunctions() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetMysqlFunctionsSql, transaction: this.Transaction); } private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types; SELECT LAST_INSERT_ID()"; public async Task TruncateMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateMysqlTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncateMysqlTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncateMysqlTypesSql, transaction: this.Transaction); } private const string CreateExtendedBioSql = "INSERT INTO extended.bios (author_name, name, bio_type) VALUES (@author_name, @name, @bio_type); SELECT LAST_INSERT_ID()"; @@ -658,14 +923,26 @@ public class CreateExtendedBioArgs }; public async Task CreateExtendedBio(CreateExtendedBioArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("author_name", args.AuthorName); + queryParams.Add("name", args.Name); + queryParams.Add("bio_type", args.BioType); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateExtendedBioSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("author_name", args.AuthorName); - queryParams.Add("name", args.Name); - queryParams.Add("bio_type", args.BioType); - await connection.ExecuteAsync(CreateExtendedBioSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(CreateExtendedBioSql, queryParams, transaction: this.Transaction); } private const string GetFirstExtendedBioByTypeSql = "SELECT author_name, name, bio_type FROM extended.bios WHERE bio_type = @bio_type LIMIT 1; SELECT LAST_INSERT_ID()"; @@ -681,22 +958,44 @@ public class GetFirstExtendedBioByTypeArgs }; public async Task GetFirstExtendedBioByType(GetFirstExtendedBioByTypeArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio_type", args.BioType); + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("bio_type", args.BioType); - var result = await connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetFirstExtendedBioByTypeSql, queryParams, transaction: this.Transaction); } private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios; SELECT LAST_INSERT_ID()"; public async Task TruncateExtendedBios() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateExtendedBiosSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncateExtendedBiosSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncateExtendedBiosSql, transaction: this.Transaction); } } } \ No newline at end of file diff --git a/examples/MySqlConnectorExample/QuerySql.cs b/examples/MySqlConnectorExample/QuerySql.cs index 1a5a7a27..e76bfb30 100644 --- a/examples/MySqlConnectorExample/QuerySql.cs +++ b/examples/MySqlConnectorExample/QuerySql.cs @@ -23,32 +23,72 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } - private string ConnectionString { get; } + private QuerySql(MySqlTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(MySqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private MySqlTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1"; public readonly record struct GetAuthorRow(long Id, string Name, string? Bio); public readonly record struct GetAuthorArgs(string Name); public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -58,21 +98,45 @@ public QuerySql(string connectionString) public readonly record struct ListAuthorsRow(long Id, string Name, string? Bio); public async Task> ListAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -81,16 +145,36 @@ public async Task> ListAuthors() public readonly record struct CreateAuthorArgs(long Id, string Name, string? Bio); public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateAuthorSql, connection)) + { + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -98,17 +182,35 @@ public async Task CreateAuthor(CreateAuthorArgs args) public readonly record struct CreateAuthorReturnIdArgs(string Name, string? Bio); public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateAuthorReturnIdSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteNonQueryAsync(); - return command.LastInsertedId; + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateAuthorReturnIdSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1"; @@ -116,25 +218,54 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByIdArgs(long Id); public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorByIdSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorByIdSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -145,22 +276,47 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByNamePatternArgs(string? NamePattern); public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorByNamePatternSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorByNamePatternSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -169,27 +325,62 @@ public async Task> GetAuthorByNamePattern(GetAut public readonly record struct DeleteAuthorArgs(string Name); public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(DeleteAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(DeleteAuthorSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(DeleteAllAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(DeleteAllAuthorsSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -197,15 +388,31 @@ public async Task DeleteAllAuthors() public readonly record struct UpdateAuthorsArgs(string? Bio); public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(UpdateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(UpdateAuthorsSql, connection)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -213,25 +420,51 @@ public async Task UpdateAuthors(UpdateAuthorsArgs args) public readonly record struct GetAuthorsByIdsArgs(long[] Ids); public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - using (var command = new MySqlCommand(transformedSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -241,28 +474,56 @@ public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs public readonly record struct GetAuthorsByIdsAndNamesArgs(long[] Ids, string[] Names); public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - using (var command = new MySqlCommand(transformedSql, connection)) - { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); - using (var reader = await command.ExecuteReaderAsync()) - { - var result = new List(); - while (await reader.ReadAsync()) + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.OpenAsync(); + using (var command = new MySqlCommand(transformedSql, connection)) + { + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -271,38 +532,80 @@ public async Task> GetAuthorsByIdsAndNames(GetA public readonly record struct CreateBookArgs(string Name, long AuthorId); public async Task CreateBook(CreateBookArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateBookSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - await command.ExecuteNonQueryAsync(); - return command.LastInsertedId; + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateBookSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name "; public readonly record struct ListAllAuthorsBooksRow(Author? Author, Book? Book); public async Task> ListAllAuthorsBooks() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -311,21 +614,45 @@ public async Task> ListAllAuthorsBooks() public readonly record struct GetDuplicateAuthorsRow(Author? Author, Author? Author2); public async Task> GetDuplicateAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -335,22 +662,47 @@ public async Task> GetDuplicateAuthors() public readonly record struct GetAuthorsByBookNameArgs(string Name); public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -359,48 +711,100 @@ public async Task> GetAuthorsByBookName(GetAuthors public readonly record struct InsertMysqlTypesArgs(byte? CBit, bool? CBool, bool? CBoolean, short? CTinyint, short? CSmallint, int? CMediumint, int? CInt, int? CInteger, long? CBigint, decimal? CDecimal, decimal? CDec, decimal? CNumeric, decimal? CFixed, double? CFloat, double? CDouble, double? CDoublePrecision, string? CChar, string? CNchar, string? CNationalChar, string? CVarchar, string? CTinytext, string? CMediumtext, string? CText, string? CLongtext, MysqlTypesCEnum? CEnum, short? CYear, DateTime? CDate, DateTime? CDatetime, DateTime? CTimestamp, byte[]? CBinary, byte[]? CVarbinary, byte[]? CTinyblob, byte[]? CBlob, byte[]? CMediumblob, byte[]? CLongblob); public async Task InsertMysqlTypes(InsertMysqlTypesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(InsertMysqlTypesSql, connection)) - { - command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.OpenAsync(); + using (var command = new MySqlCommand(InsertMysqlTypesSql, connection)) + { + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertMysqlTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -470,57 +874,118 @@ public async Task InsertMysqlTypesBatch(List args) public readonly record struct GetMysqlTypesRow(bool? CBool, bool? CBoolean, short? CTinyint, short? CSmallint, int? CMediumint, int? CInt, int? CInteger, long? CBigint, double? CFloat, decimal? CDecimal, decimal? CDec, decimal? CNumeric, decimal? CFixed, double? CDouble, double? CDoublePrecision, short? CYear, DateTime? CDate, string? CTime, DateTime? CDatetime, DateTime? CTimestamp, string? CChar, string? CNchar, string? CNationalChar, string? CVarchar, string? CTinytext, string? CMediumtext, string? CText, string? CLongtext, MysqlTypesCEnum? CEnum, byte? CBit, byte[]? CBinary, byte[]? CVarbinary, byte[]? CTinyblob, byte[]? CBlob, byte[]? CMediumblob, byte[]? CLongblob); public async Task GetMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlTypesSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlTypesSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlTypesRow + if (await reader.ReadAsync()) { - CBool = reader.IsDBNull(0) ? null : reader.GetBoolean(0), - CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), - CTinyint = reader.IsDBNull(2) ? null : reader.GetInt16(2), - CSmallint = reader.IsDBNull(3) ? null : reader.GetInt16(3), - CMediumint = reader.IsDBNull(4) ? null : reader.GetInt32(4), - CInt = reader.IsDBNull(5) ? null : reader.GetInt32(5), - CInteger = reader.IsDBNull(6) ? null : reader.GetInt32(6), - CBigint = reader.IsDBNull(7) ? null : reader.GetInt64(7), - CFloat = reader.IsDBNull(8) ? null : reader.GetDouble(8), - CDecimal = reader.IsDBNull(9) ? null : reader.GetDecimal(9), - CDec = reader.IsDBNull(10) ? null : reader.GetDecimal(10), - CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), - CFixed = reader.IsDBNull(12) ? null : reader.GetDecimal(12), - CDouble = reader.IsDBNull(13) ? null : reader.GetDouble(13), - CDoublePrecision = reader.IsDBNull(14) ? null : reader.GetDouble(14), - CYear = reader.IsDBNull(15) ? null : reader.GetInt16(15), - CDate = reader.IsDBNull(16) ? null : reader.GetDateTime(16), - CTime = reader.IsDBNull(17) ? null : reader.GetString(17), - CDatetime = reader.IsDBNull(18) ? null : reader.GetDateTime(18), - CTimestamp = reader.IsDBNull(19) ? null : reader.GetDateTime(19), - CChar = reader.IsDBNull(20) ? null : reader.GetString(20), - CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), - CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), - CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), - CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), - CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), - CText = reader.IsDBNull(26) ? null : reader.GetString(26), - CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), - CEnum = reader.IsDBNull(28) ? null : reader.GetString(28).ToMysqlTypesCEnum(), - CBit = reader.IsDBNull(29) ? null : reader.GetFieldValue(29), - CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), - CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), - CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), - CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), - CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), - CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) - }; + return new GetMysqlTypesRow + { + CBool = reader.IsDBNull(0) ? null : reader.GetBoolean(0), + CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CTinyint = reader.IsDBNull(2) ? null : reader.GetInt16(2), + CSmallint = reader.IsDBNull(3) ? null : reader.GetInt16(3), + CMediumint = reader.IsDBNull(4) ? null : reader.GetInt32(4), + CInt = reader.IsDBNull(5) ? null : reader.GetInt32(5), + CInteger = reader.IsDBNull(6) ? null : reader.GetInt32(6), + CBigint = reader.IsDBNull(7) ? null : reader.GetInt64(7), + CFloat = reader.IsDBNull(8) ? null : reader.GetDouble(8), + CDecimal = reader.IsDBNull(9) ? null : reader.GetDecimal(9), + CDec = reader.IsDBNull(10) ? null : reader.GetDecimal(10), + CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), + CFixed = reader.IsDBNull(12) ? null : reader.GetDecimal(12), + CDouble = reader.IsDBNull(13) ? null : reader.GetDouble(13), + CDoublePrecision = reader.IsDBNull(14) ? null : reader.GetDouble(14), + CYear = reader.IsDBNull(15) ? null : reader.GetInt16(15), + CDate = reader.IsDBNull(16) ? null : reader.GetDateTime(16), + CTime = reader.IsDBNull(17) ? null : reader.GetString(17), + CDatetime = reader.IsDBNull(18) ? null : reader.GetDateTime(18), + CTimestamp = reader.IsDBNull(19) ? null : reader.GetDateTime(19), + CChar = reader.IsDBNull(20) ? null : reader.GetString(20), + CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), + CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), + CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), + CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), + CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), + CText = reader.IsDBNull(26) ? null : reader.GetString(26), + CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), + CEnum = reader.IsDBNull(28) ? null : reader.GetString(28).ToMysqlTypesCEnum(), + CBit = reader.IsDBNull(29) ? null : reader.GetFieldValue(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlTypesRow + { + CBool = reader.IsDBNull(0) ? null : reader.GetBoolean(0), + CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CTinyint = reader.IsDBNull(2) ? null : reader.GetInt16(2), + CSmallint = reader.IsDBNull(3) ? null : reader.GetInt16(3), + CMediumint = reader.IsDBNull(4) ? null : reader.GetInt32(4), + CInt = reader.IsDBNull(5) ? null : reader.GetInt32(5), + CInteger = reader.IsDBNull(6) ? null : reader.GetInt32(6), + CBigint = reader.IsDBNull(7) ? null : reader.GetInt64(7), + CFloat = reader.IsDBNull(8) ? null : reader.GetDouble(8), + CDecimal = reader.IsDBNull(9) ? null : reader.GetDecimal(9), + CDec = reader.IsDBNull(10) ? null : reader.GetDecimal(10), + CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), + CFixed = reader.IsDBNull(12) ? null : reader.GetDecimal(12), + CDouble = reader.IsDBNull(13) ? null : reader.GetDouble(13), + CDoublePrecision = reader.IsDBNull(14) ? null : reader.GetDouble(14), + CYear = reader.IsDBNull(15) ? null : reader.GetInt16(15), + CDate = reader.IsDBNull(16) ? null : reader.GetDateTime(16), + CTime = reader.IsDBNull(17) ? null : reader.GetString(17), + CDatetime = reader.IsDBNull(18) ? null : reader.GetDateTime(18), + CTimestamp = reader.IsDBNull(19) ? null : reader.GetDateTime(19), + CChar = reader.IsDBNull(20) ? null : reader.GetString(20), + CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), + CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), + CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), + CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), + CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), + CText = reader.IsDBNull(26) ? null : reader.GetString(26), + CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), + CEnum = reader.IsDBNull(28) ? null : reader.GetString(28).ToMysqlTypesCEnum(), + CBit = reader.IsDBNull(29) ? null : reader.GetFieldValue(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } + } } return null; @@ -530,57 +995,118 @@ public async Task InsertMysqlTypesBatch(List args) public readonly record struct GetMysqlTypesCntRow(long Cnt, bool? CBool, bool? CBoolean, byte? CBit, short? CTinyint, short? CSmallint, int? CMediumint, int? CInt, int? CInteger, long? CBigint, double? CFloat, decimal? CNumeric, decimal? CDecimal, decimal? CDec, decimal? CFixed, double? CDouble, double? CDoublePrecision, string? CChar, string? CNchar, string? CNationalChar, string? CVarchar, string? CTinytext, string? CMediumtext, string? CText, string? CLongtext, MysqlTypesCEnum? CEnum, short? CYear, DateTime? CDate, DateTime? CDatetime, DateTime? CTimestamp, byte[]? CBinary, byte[]? CVarbinary, byte[]? CTinyblob, byte[]? CBlob, byte[]? CMediumblob, byte[]? CLongblob); public async Task GetMysqlTypesCnt() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlTypesCntSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlTypesCntSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlTypesCntRow + if (await reader.ReadAsync()) { - Cnt = reader.GetInt64(0), - CBool = reader.IsDBNull(1) ? null : reader.GetBoolean(1), - CBoolean = reader.IsDBNull(2) ? null : reader.GetBoolean(2), - CBit = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), - CTinyint = reader.IsDBNull(4) ? null : reader.GetInt16(4), - CSmallint = reader.IsDBNull(5) ? null : reader.GetInt16(5), - CMediumint = reader.IsDBNull(6) ? null : reader.GetInt32(6), - CInt = reader.IsDBNull(7) ? null : reader.GetInt32(7), - CInteger = reader.IsDBNull(8) ? null : reader.GetInt32(8), - CBigint = reader.IsDBNull(9) ? null : reader.GetInt64(9), - CFloat = reader.IsDBNull(10) ? null : reader.GetDouble(10), - CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), - CDecimal = reader.IsDBNull(12) ? null : reader.GetDecimal(12), - CDec = reader.IsDBNull(13) ? null : reader.GetDecimal(13), - CFixed = reader.IsDBNull(14) ? null : reader.GetDecimal(14), - CDouble = reader.IsDBNull(15) ? null : reader.GetDouble(15), - CDoublePrecision = reader.IsDBNull(16) ? null : reader.GetDouble(16), - CChar = reader.IsDBNull(17) ? null : reader.GetString(17), - CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), - CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), - CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), - CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), - CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), - CText = reader.IsDBNull(23) ? null : reader.GetString(23), - CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), - CEnum = reader.IsDBNull(25) ? null : reader.GetString(25).ToMysqlTypesCEnum(), - CYear = reader.IsDBNull(26) ? null : reader.GetInt16(26), - CDate = reader.IsDBNull(27) ? null : reader.GetDateTime(27), - CDatetime = reader.IsDBNull(28) ? null : reader.GetDateTime(28), - CTimestamp = reader.IsDBNull(29) ? null : reader.GetDateTime(29), - CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), - CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), - CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), - CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), - CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), - CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) - }; + return new GetMysqlTypesCntRow + { + Cnt = reader.GetInt64(0), + CBool = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CBoolean = reader.IsDBNull(2) ? null : reader.GetBoolean(2), + CBit = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + CTinyint = reader.IsDBNull(4) ? null : reader.GetInt16(4), + CSmallint = reader.IsDBNull(5) ? null : reader.GetInt16(5), + CMediumint = reader.IsDBNull(6) ? null : reader.GetInt32(6), + CInt = reader.IsDBNull(7) ? null : reader.GetInt32(7), + CInteger = reader.IsDBNull(8) ? null : reader.GetInt32(8), + CBigint = reader.IsDBNull(9) ? null : reader.GetInt64(9), + CFloat = reader.IsDBNull(10) ? null : reader.GetDouble(10), + CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), + CDecimal = reader.IsDBNull(12) ? null : reader.GetDecimal(12), + CDec = reader.IsDBNull(13) ? null : reader.GetDecimal(13), + CFixed = reader.IsDBNull(14) ? null : reader.GetDecimal(14), + CDouble = reader.IsDBNull(15) ? null : reader.GetDouble(15), + CDoublePrecision = reader.IsDBNull(16) ? null : reader.GetDouble(16), + CChar = reader.IsDBNull(17) ? null : reader.GetString(17), + CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), + CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), + CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), + CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), + CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), + CText = reader.IsDBNull(23) ? null : reader.GetString(23), + CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), + CEnum = reader.IsDBNull(25) ? null : reader.GetString(25).ToMysqlTypesCEnum(), + CYear = reader.IsDBNull(26) ? null : reader.GetInt16(26), + CDate = reader.IsDBNull(27) ? null : reader.GetDateTime(27), + CDatetime = reader.IsDBNull(28) ? null : reader.GetDateTime(28), + CTimestamp = reader.IsDBNull(29) ? null : reader.GetDateTime(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlTypesCntRow + { + Cnt = reader.GetInt64(0), + CBool = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CBoolean = reader.IsDBNull(2) ? null : reader.GetBoolean(2), + CBit = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + CTinyint = reader.IsDBNull(4) ? null : reader.GetInt16(4), + CSmallint = reader.IsDBNull(5) ? null : reader.GetInt16(5), + CMediumint = reader.IsDBNull(6) ? null : reader.GetInt32(6), + CInt = reader.IsDBNull(7) ? null : reader.GetInt32(7), + CInteger = reader.IsDBNull(8) ? null : reader.GetInt32(8), + CBigint = reader.IsDBNull(9) ? null : reader.GetInt64(9), + CFloat = reader.IsDBNull(10) ? null : reader.GetDouble(10), + CNumeric = reader.IsDBNull(11) ? null : reader.GetDecimal(11), + CDecimal = reader.IsDBNull(12) ? null : reader.GetDecimal(12), + CDec = reader.IsDBNull(13) ? null : reader.GetDecimal(13), + CFixed = reader.IsDBNull(14) ? null : reader.GetDecimal(14), + CDouble = reader.IsDBNull(15) ? null : reader.GetDouble(15), + CDoublePrecision = reader.IsDBNull(16) ? null : reader.GetDouble(16), + CChar = reader.IsDBNull(17) ? null : reader.GetString(17), + CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), + CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), + CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), + CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), + CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), + CText = reader.IsDBNull(23) ? null : reader.GetString(23), + CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), + CEnum = reader.IsDBNull(25) ? null : reader.GetString(25).ToMysqlTypesCEnum(), + CYear = reader.IsDBNull(26) ? null : reader.GetInt16(26), + CDate = reader.IsDBNull(27) ? null : reader.GetDateTime(27), + CDatetime = reader.IsDBNull(28) ? null : reader.GetDateTime(28), + CTimestamp = reader.IsDBNull(29) ? null : reader.GetDateTime(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } + } } return null; @@ -590,25 +1116,54 @@ public async Task InsertMysqlTypesBatch(List args) public readonly record struct GetMysqlFunctionsRow(int? MaxInt, string? MaxVarchar, DateTime MaxTimestamp, long MaxBigint); public async Task GetMysqlFunctions() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlFunctionsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlFunctionsSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlFunctionsRow + if (await reader.ReadAsync()) { - MaxInt = reader.IsDBNull(0) ? null : reader.GetInt32(0), - MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), - MaxTimestamp = reader.GetDateTime(2), - MaxBigint = reader.GetInt64(3) - }; + return new GetMysqlFunctionsRow + { + MaxInt = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2), + MaxBigint = reader.GetInt64(3) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlFunctionsRow + { + MaxInt = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2), + MaxBigint = reader.GetInt64(3) + }; + } + } } return null; @@ -617,13 +1172,30 @@ public async Task InsertMysqlTypesBatch(List args) private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types"; public async Task TruncateMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(TruncateMysqlTypesSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(TruncateMysqlTypesSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateMysqlTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -631,16 +1203,36 @@ public async Task TruncateMysqlTypes() public readonly record struct CreateExtendedBioArgs(string? AuthorName, string? Name, ExtendedBiosBioType? BioType); public async Task CreateExtendedBio(CreateExtendedBioArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateExtendedBioSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateExtendedBioSql, connection)) + { + command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateExtendedBioSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -649,25 +1241,54 @@ public async Task CreateExtendedBio(CreateExtendedBioArgs args) public readonly record struct GetFirstExtendedBioByTypeArgs(ExtendedBiosBioType? BioType); public async Task GetFirstExtendedBioByType(GetFirstExtendedBioByTypeArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetFirstExtendedBioByTypeSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetFirstExtendedBioByTypeSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetFirstExtendedBioByTypeRow + if (await reader.ReadAsync()) { - AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), - Name = reader.IsDBNull(1) ? null : reader.GetString(1), - BioType = reader.IsDBNull(2) ? null : reader.GetString(2).ToExtendedBiosBioType() - }; + return new GetFirstExtendedBioByTypeRow + { + AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), + Name = reader.IsDBNull(1) ? null : reader.GetString(1), + BioType = reader.IsDBNull(2) ? null : reader.GetString(2).ToExtendedBiosBioType() + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetFirstExtendedBioByTypeSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetFirstExtendedBioByTypeRow + { + AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), + Name = reader.IsDBNull(1) ? null : reader.GetString(1), + BioType = reader.IsDBNull(2) ? null : reader.GetString(2).ToExtendedBiosBioType() + }; + } + } } return null; @@ -676,13 +1297,30 @@ public async Task CreateExtendedBio(CreateExtendedBioArgs args) private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios"; public async Task TruncateExtendedBios() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(TruncateExtendedBiosSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(TruncateExtendedBiosSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateExtendedBiosSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } } \ No newline at end of file diff --git a/examples/MySqlConnectorLegacyExample/QuerySql.cs b/examples/MySqlConnectorLegacyExample/QuerySql.cs index b0119b74..d81c4d13 100644 --- a/examples/MySqlConnectorLegacyExample/QuerySql.cs +++ b/examples/MySqlConnectorLegacyExample/QuerySql.cs @@ -24,6 +24,17 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } + private QuerySql(MySqlTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(MySqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private MySqlTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1"; @@ -39,25 +50,54 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -72,21 +112,45 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -100,16 +164,36 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateAuthorSql, connection)) + { + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -121,17 +205,35 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateAuthorReturnIdSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteNonQueryAsync(); - return command.LastInsertedId; + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateAuthorReturnIdSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1"; @@ -147,25 +249,54 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorByIdSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorByIdSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -184,22 +315,47 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorByNamePatternSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorByNamePatternSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -211,27 +367,62 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(DeleteAuthorSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(DeleteAuthorSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(DeleteAllAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(DeleteAllAuthorsSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -242,15 +433,31 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(UpdateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(UpdateAuthorsSql, connection)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -266,25 +473,51 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - using (var command = new MySqlCommand(transformedSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -303,28 +536,56 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - using (var command = new MySqlCommand(transformedSql, connection)) - { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); - using (var reader = await command.ExecuteReaderAsync()) - { - var result = new List(); - while (await reader.ReadAsync()) + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.OpenAsync(); + using (var command = new MySqlCommand(transformedSql, connection)) + { + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -337,17 +598,35 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateBookSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - await command.ExecuteNonQueryAsync(); - return command.LastInsertedId; + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateBookSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + await command.ExecuteNonQueryAsync(); + return command.LastInsertedId; + } } private const string ListAllAuthorsBooksSql = "SELECT authors.id, authors.name, authors.bio, books.id, books.name, books.author_id, books.description FROM authors JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -358,21 +637,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -385,21 +688,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -418,22 +745,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -479,48 +831,100 @@ public class InsertMysqlTypesArgs }; public async Task InsertMysqlTypes(InsertMysqlTypesArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(InsertMysqlTypesSql, connection)) - { - command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + using (var connection = new MySqlConnection(ConnectionString)) + { + await connection.OpenAsync(); + using (var command = new MySqlCommand(InsertMysqlTypesSql, connection)) + { + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertMysqlTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bool", args.CBool ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyint", args.CTinyint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumint", args.CMediumint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_int", args.CInt ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_dec", args.CDec ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_fixed", args.CFixed ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_float", args.CFloat ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double", args.CDouble ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_nchar", args.CNchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_national_char", args.CNationalChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinytext", args.CTinytext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumtext", args.CMediumtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longtext", args.CLongtext ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_enum", args.CEnum ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_year", args.CYear ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_datetime", args.CDatetime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_binary", args.CBinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varbinary", args.CVarbinary ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_tinyblob", args.CTinyblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_mediumblob", args.CMediumblob ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_longblob", args.CLongblob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -664,57 +1068,118 @@ public class GetMysqlTypesRow }; public async Task GetMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlTypesSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlTypesSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlTypesRow + if (await reader.ReadAsync()) { - CBool = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), - CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), - CTinyint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), - CSmallint = reader.IsDBNull(3) ? (short? )null : reader.GetInt16(3), - CMediumint = reader.IsDBNull(4) ? (int? )null : reader.GetInt32(4), - CInt = reader.IsDBNull(5) ? (int? )null : reader.GetInt32(5), - CInteger = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), - CBigint = reader.IsDBNull(7) ? (long? )null : reader.GetInt64(7), - CFloat = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), - CDecimal = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), - CDec = reader.IsDBNull(10) ? (decimal? )null : reader.GetDecimal(10), - CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), - CFixed = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), - CDouble = reader.IsDBNull(13) ? (double? )null : reader.GetDouble(13), - CDoublePrecision = reader.IsDBNull(14) ? (double? )null : reader.GetDouble(14), - CYear = reader.IsDBNull(15) ? (short? )null : reader.GetInt16(15), - CDate = reader.IsDBNull(16) ? (DateTime? )null : reader.GetDateTime(16), - CTime = reader.IsDBNull(17) ? null : reader.GetString(17), - CDatetime = reader.IsDBNull(18) ? (DateTime? )null : reader.GetDateTime(18), - CTimestamp = reader.IsDBNull(19) ? (DateTime? )null : reader.GetDateTime(19), - CChar = reader.IsDBNull(20) ? null : reader.GetString(20), - CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), - CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), - CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), - CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), - CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), - CText = reader.IsDBNull(26) ? null : reader.GetString(26), - CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), - CEnum = reader.IsDBNull(28) ? (MysqlTypesCEnum? )null : reader.GetString(28).ToMysqlTypesCEnum(), - CBit = reader.IsDBNull(29) ? (byte? )null : reader.GetFieldValue(29), - CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), - CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), - CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), - CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), - CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), - CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) - }; + return new GetMysqlTypesRow + { + CBool = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), + CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CTinyint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), + CSmallint = reader.IsDBNull(3) ? (short? )null : reader.GetInt16(3), + CMediumint = reader.IsDBNull(4) ? (int? )null : reader.GetInt32(4), + CInt = reader.IsDBNull(5) ? (int? )null : reader.GetInt32(5), + CInteger = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), + CBigint = reader.IsDBNull(7) ? (long? )null : reader.GetInt64(7), + CFloat = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), + CDecimal = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), + CDec = reader.IsDBNull(10) ? (decimal? )null : reader.GetDecimal(10), + CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), + CFixed = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), + CDouble = reader.IsDBNull(13) ? (double? )null : reader.GetDouble(13), + CDoublePrecision = reader.IsDBNull(14) ? (double? )null : reader.GetDouble(14), + CYear = reader.IsDBNull(15) ? (short? )null : reader.GetInt16(15), + CDate = reader.IsDBNull(16) ? (DateTime? )null : reader.GetDateTime(16), + CTime = reader.IsDBNull(17) ? null : reader.GetString(17), + CDatetime = reader.IsDBNull(18) ? (DateTime? )null : reader.GetDateTime(18), + CTimestamp = reader.IsDBNull(19) ? (DateTime? )null : reader.GetDateTime(19), + CChar = reader.IsDBNull(20) ? null : reader.GetString(20), + CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), + CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), + CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), + CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), + CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), + CText = reader.IsDBNull(26) ? null : reader.GetString(26), + CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), + CEnum = reader.IsDBNull(28) ? (MysqlTypesCEnum? )null : reader.GetString(28).ToMysqlTypesCEnum(), + CBit = reader.IsDBNull(29) ? (byte? )null : reader.GetFieldValue(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlTypesRow + { + CBool = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), + CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CTinyint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), + CSmallint = reader.IsDBNull(3) ? (short? )null : reader.GetInt16(3), + CMediumint = reader.IsDBNull(4) ? (int? )null : reader.GetInt32(4), + CInt = reader.IsDBNull(5) ? (int? )null : reader.GetInt32(5), + CInteger = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), + CBigint = reader.IsDBNull(7) ? (long? )null : reader.GetInt64(7), + CFloat = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), + CDecimal = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), + CDec = reader.IsDBNull(10) ? (decimal? )null : reader.GetDecimal(10), + CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), + CFixed = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), + CDouble = reader.IsDBNull(13) ? (double? )null : reader.GetDouble(13), + CDoublePrecision = reader.IsDBNull(14) ? (double? )null : reader.GetDouble(14), + CYear = reader.IsDBNull(15) ? (short? )null : reader.GetInt16(15), + CDate = reader.IsDBNull(16) ? (DateTime? )null : reader.GetDateTime(16), + CTime = reader.IsDBNull(17) ? null : reader.GetString(17), + CDatetime = reader.IsDBNull(18) ? (DateTime? )null : reader.GetDateTime(18), + CTimestamp = reader.IsDBNull(19) ? (DateTime? )null : reader.GetDateTime(19), + CChar = reader.IsDBNull(20) ? null : reader.GetString(20), + CNchar = reader.IsDBNull(21) ? null : reader.GetString(21), + CNationalChar = reader.IsDBNull(22) ? null : reader.GetString(22), + CVarchar = reader.IsDBNull(23) ? null : reader.GetString(23), + CTinytext = reader.IsDBNull(24) ? null : reader.GetString(24), + CMediumtext = reader.IsDBNull(25) ? null : reader.GetString(25), + CText = reader.IsDBNull(26) ? null : reader.GetString(26), + CLongtext = reader.IsDBNull(27) ? null : reader.GetString(27), + CEnum = reader.IsDBNull(28) ? (MysqlTypesCEnum? )null : reader.GetString(28).ToMysqlTypesCEnum(), + CBit = reader.IsDBNull(29) ? (byte? )null : reader.GetFieldValue(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } + } } return null; @@ -762,57 +1227,118 @@ public class GetMysqlTypesCntRow }; public async Task GetMysqlTypesCnt() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlTypesCntSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlTypesCntSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlTypesCntRow + if (await reader.ReadAsync()) { - Cnt = reader.GetInt64(0), - CBool = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), - CBoolean = reader.IsDBNull(2) ? (bool? )null : reader.GetBoolean(2), - CBit = reader.IsDBNull(3) ? (byte? )null : reader.GetFieldValue(3), - CTinyint = reader.IsDBNull(4) ? (short? )null : reader.GetInt16(4), - CSmallint = reader.IsDBNull(5) ? (short? )null : reader.GetInt16(5), - CMediumint = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), - CInt = reader.IsDBNull(7) ? (int? )null : reader.GetInt32(7), - CInteger = reader.IsDBNull(8) ? (int? )null : reader.GetInt32(8), - CBigint = reader.IsDBNull(9) ? (long? )null : reader.GetInt64(9), - CFloat = reader.IsDBNull(10) ? (double? )null : reader.GetDouble(10), - CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), - CDecimal = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), - CDec = reader.IsDBNull(13) ? (decimal? )null : reader.GetDecimal(13), - CFixed = reader.IsDBNull(14) ? (decimal? )null : reader.GetDecimal(14), - CDouble = reader.IsDBNull(15) ? (double? )null : reader.GetDouble(15), - CDoublePrecision = reader.IsDBNull(16) ? (double? )null : reader.GetDouble(16), - CChar = reader.IsDBNull(17) ? null : reader.GetString(17), - CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), - CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), - CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), - CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), - CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), - CText = reader.IsDBNull(23) ? null : reader.GetString(23), - CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), - CEnum = reader.IsDBNull(25) ? (MysqlTypesCEnum? )null : reader.GetString(25).ToMysqlTypesCEnum(), - CYear = reader.IsDBNull(26) ? (short? )null : reader.GetInt16(26), - CDate = reader.IsDBNull(27) ? (DateTime? )null : reader.GetDateTime(27), - CDatetime = reader.IsDBNull(28) ? (DateTime? )null : reader.GetDateTime(28), - CTimestamp = reader.IsDBNull(29) ? (DateTime? )null : reader.GetDateTime(29), - CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), - CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), - CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), - CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), - CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), - CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) - }; + return new GetMysqlTypesCntRow + { + Cnt = reader.GetInt64(0), + CBool = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CBoolean = reader.IsDBNull(2) ? (bool? )null : reader.GetBoolean(2), + CBit = reader.IsDBNull(3) ? (byte? )null : reader.GetFieldValue(3), + CTinyint = reader.IsDBNull(4) ? (short? )null : reader.GetInt16(4), + CSmallint = reader.IsDBNull(5) ? (short? )null : reader.GetInt16(5), + CMediumint = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), + CInt = reader.IsDBNull(7) ? (int? )null : reader.GetInt32(7), + CInteger = reader.IsDBNull(8) ? (int? )null : reader.GetInt32(8), + CBigint = reader.IsDBNull(9) ? (long? )null : reader.GetInt64(9), + CFloat = reader.IsDBNull(10) ? (double? )null : reader.GetDouble(10), + CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), + CDecimal = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), + CDec = reader.IsDBNull(13) ? (decimal? )null : reader.GetDecimal(13), + CFixed = reader.IsDBNull(14) ? (decimal? )null : reader.GetDecimal(14), + CDouble = reader.IsDBNull(15) ? (double? )null : reader.GetDouble(15), + CDoublePrecision = reader.IsDBNull(16) ? (double? )null : reader.GetDouble(16), + CChar = reader.IsDBNull(17) ? null : reader.GetString(17), + CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), + CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), + CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), + CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), + CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), + CText = reader.IsDBNull(23) ? null : reader.GetString(23), + CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), + CEnum = reader.IsDBNull(25) ? (MysqlTypesCEnum? )null : reader.GetString(25).ToMysqlTypesCEnum(), + CYear = reader.IsDBNull(26) ? (short? )null : reader.GetInt16(26), + CDate = reader.IsDBNull(27) ? (DateTime? )null : reader.GetDateTime(27), + CDatetime = reader.IsDBNull(28) ? (DateTime? )null : reader.GetDateTime(28), + CTimestamp = reader.IsDBNull(29) ? (DateTime? )null : reader.GetDateTime(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlTypesCntRow + { + Cnt = reader.GetInt64(0), + CBool = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CBoolean = reader.IsDBNull(2) ? (bool? )null : reader.GetBoolean(2), + CBit = reader.IsDBNull(3) ? (byte? )null : reader.GetFieldValue(3), + CTinyint = reader.IsDBNull(4) ? (short? )null : reader.GetInt16(4), + CSmallint = reader.IsDBNull(5) ? (short? )null : reader.GetInt16(5), + CMediumint = reader.IsDBNull(6) ? (int? )null : reader.GetInt32(6), + CInt = reader.IsDBNull(7) ? (int? )null : reader.GetInt32(7), + CInteger = reader.IsDBNull(8) ? (int? )null : reader.GetInt32(8), + CBigint = reader.IsDBNull(9) ? (long? )null : reader.GetInt64(9), + CFloat = reader.IsDBNull(10) ? (double? )null : reader.GetDouble(10), + CNumeric = reader.IsDBNull(11) ? (decimal? )null : reader.GetDecimal(11), + CDecimal = reader.IsDBNull(12) ? (decimal? )null : reader.GetDecimal(12), + CDec = reader.IsDBNull(13) ? (decimal? )null : reader.GetDecimal(13), + CFixed = reader.IsDBNull(14) ? (decimal? )null : reader.GetDecimal(14), + CDouble = reader.IsDBNull(15) ? (double? )null : reader.GetDouble(15), + CDoublePrecision = reader.IsDBNull(16) ? (double? )null : reader.GetDouble(16), + CChar = reader.IsDBNull(17) ? null : reader.GetString(17), + CNchar = reader.IsDBNull(18) ? null : reader.GetString(18), + CNationalChar = reader.IsDBNull(19) ? null : reader.GetString(19), + CVarchar = reader.IsDBNull(20) ? null : reader.GetString(20), + CTinytext = reader.IsDBNull(21) ? null : reader.GetString(21), + CMediumtext = reader.IsDBNull(22) ? null : reader.GetString(22), + CText = reader.IsDBNull(23) ? null : reader.GetString(23), + CLongtext = reader.IsDBNull(24) ? null : reader.GetString(24), + CEnum = reader.IsDBNull(25) ? (MysqlTypesCEnum? )null : reader.GetString(25).ToMysqlTypesCEnum(), + CYear = reader.IsDBNull(26) ? (short? )null : reader.GetInt16(26), + CDate = reader.IsDBNull(27) ? (DateTime? )null : reader.GetDateTime(27), + CDatetime = reader.IsDBNull(28) ? (DateTime? )null : reader.GetDateTime(28), + CTimestamp = reader.IsDBNull(29) ? (DateTime? )null : reader.GetDateTime(29), + CBinary = reader.IsDBNull(30) ? null : reader.GetFieldValue(30), + CVarbinary = reader.IsDBNull(31) ? null : reader.GetFieldValue(31), + CTinyblob = reader.IsDBNull(32) ? null : reader.GetFieldValue(32), + CBlob = reader.IsDBNull(33) ? null : reader.GetFieldValue(33), + CMediumblob = reader.IsDBNull(34) ? null : reader.GetFieldValue(34), + CLongblob = reader.IsDBNull(35) ? null : reader.GetFieldValue(35) + }; + } + } } return null; @@ -828,25 +1354,54 @@ public class GetMysqlFunctionsRow }; public async Task GetMysqlFunctions() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetMysqlFunctionsSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetMysqlFunctionsSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetMysqlFunctionsRow + if (await reader.ReadAsync()) { - MaxInt = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), - MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), - MaxTimestamp = reader.GetDateTime(2), - MaxBigint = reader.GetInt64(3) - }; + return new GetMysqlFunctionsRow + { + MaxInt = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2), + MaxBigint = reader.GetInt64(3) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetMysqlFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetMysqlFunctionsRow + { + MaxInt = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2), + MaxBigint = reader.GetInt64(3) + }; + } + } } return null; @@ -855,13 +1410,30 @@ public async Task GetMysqlFunctions() private const string TruncateMysqlTypesSql = "TRUNCATE TABLE mysql_types"; public async Task TruncateMysqlTypes() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(TruncateMysqlTypesSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(TruncateMysqlTypesSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateMysqlTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -874,16 +1446,36 @@ public class CreateExtendedBioArgs }; public async Task CreateExtendedBio(CreateExtendedBioArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(CreateExtendedBioSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(CreateExtendedBioSql, connection)) + { + command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateExtendedBioSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@author_name", args.AuthorName ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@name", args.Name ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -900,25 +1492,54 @@ public class GetFirstExtendedBioByTypeArgs }; public async Task GetFirstExtendedBioByType(GetFirstExtendedBioByTypeArgs args) { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(GetFirstExtendedBioByTypeSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new MySqlCommand(GetFirstExtendedBioByTypeSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetFirstExtendedBioByTypeRow + if (await reader.ReadAsync()) { - AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), - Name = reader.IsDBNull(1) ? null : reader.GetString(1), - BioType = reader.IsDBNull(2) ? (ExtendedBiosBioType? )null : reader.GetString(2).ToExtendedBiosBioType() - }; + return new GetFirstExtendedBioByTypeRow + { + AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), + Name = reader.IsDBNull(1) ? null : reader.GetString(1), + BioType = reader.IsDBNull(2) ? (ExtendedBiosBioType? )null : reader.GetString(2).ToExtendedBiosBioType() + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetFirstExtendedBioByTypeSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio_type", args.BioType ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetFirstExtendedBioByTypeRow + { + AuthorName = reader.IsDBNull(0) ? null : reader.GetString(0), + Name = reader.IsDBNull(1) ? null : reader.GetString(1), + BioType = reader.IsDBNull(2) ? (ExtendedBiosBioType? )null : reader.GetString(2).ToExtendedBiosBioType() + }; + } + } } return null; @@ -927,13 +1548,30 @@ public async Task GetFirstExtendedBioByType(GetFir private const string TruncateExtendedBiosSql = "TRUNCATE TABLE extended.bios"; public async Task TruncateExtendedBios() { - using (var connection = new MySqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new MySqlCommand(TruncateExtendedBiosSql, connection)) + using (var connection = new MySqlConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new MySqlCommand(TruncateExtendedBiosSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateExtendedBiosSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } } diff --git a/examples/NpgsqlDapperExample/QuerySql.cs b/examples/NpgsqlDapperExample/QuerySql.cs index a871c1d8..f2464c6b 100644 --- a/examples/NpgsqlDapperExample/QuerySql.cs +++ b/examples/NpgsqlDapperExample/QuerySql.cs @@ -22,7 +22,20 @@ public QuerySql(string connectionString) Utils.ConfigureSqlMapper(); } - private string ConnectionString { get; } + private QuerySql(NpgsqlTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + Utils.ConfigureSqlMapper(); + } + + public static QuerySql WithTransaction(NpgsqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private NpgsqlTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; public class GetAuthorRow @@ -37,13 +50,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; @@ -55,11 +78,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio) RETURNING id, name, bio"; @@ -77,15 +110,25 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - var result = await connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio) RETURNING id"; @@ -100,13 +143,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -122,13 +175,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; @@ -144,13 +207,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; @@ -160,21 +233,45 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string TruncateAuthorsSql = "TRUNCATE TABLE authors CASCADE"; public async Task TruncateAuthors() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(TruncateAuthorsSql); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateAuthorsSql); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(TruncateAuthorsSql, transaction: this.Transaction); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; @@ -184,12 +281,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) "; @@ -205,13 +312,23 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("longArr_1", args.LongArr1); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorsByIdsSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("longArr_1", args.LongArr1); - var result = await connection.QueryAsync(GetAuthorsByIdsSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorsByIdsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) AND name = ANY ( @stringArr_2 :: TEXT [ ] ) "; @@ -228,14 +345,24 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("longArr_1", args.LongArr1); + queryParams.Add("stringArr_2", args.StringArr2); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("longArr_1", args.LongArr1); - queryParams.Add("stringArr_2", args.StringArr2); - var result = await connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams); - return result.AsList(); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams); + return result.AsList(); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id) RETURNING id"; @@ -250,13 +377,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -267,20 +404,44 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -293,20 +454,44 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -325,21 +510,46 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -371,32 +581,44 @@ public class InsertPostgresTypesArgs }; public async Task InsertPostgresTypes(InsertPostgresTypesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) - { - var queryParams = new Dictionary(); - queryParams.Add("c_boolean", args.CBoolean); - queryParams.Add("c_bit", args.CBit); - queryParams.Add("c_smallint", args.CSmallint); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_bigint", args.CBigint); - queryParams.Add("c_real", args.CReal); - queryParams.Add("c_numeric", args.CNumeric); - queryParams.Add("c_decimal", args.CDecimal); - queryParams.Add("c_double_precision", args.CDoublePrecision); - queryParams.Add("c_money", args.CMoney); - queryParams.Add("c_date", args.CDate); - queryParams.Add("c_time", args.CTime); - queryParams.Add("c_timestamp", args.CTimestamp); - queryParams.Add("c_timestamp_with_tz", args.CTimestampWithTz); - queryParams.Add("c_char", args.CChar); - queryParams.Add("c_varchar", args.CVarchar); - queryParams.Add("c_character_varying", args.CCharacterVarying); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_bytea", args.CBytea); - queryParams.Add("c_text_array", args.CTextArray); - queryParams.Add("c_integer_array", args.CIntegerArray); - await connection.ExecuteAsync(InsertPostgresTypesSql, queryParams); + var queryParams = new Dictionary(); + queryParams.Add("c_boolean", args.CBoolean); + queryParams.Add("c_bit", args.CBit); + queryParams.Add("c_smallint", args.CSmallint); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_bigint", args.CBigint); + queryParams.Add("c_real", args.CReal); + queryParams.Add("c_numeric", args.CNumeric); + queryParams.Add("c_decimal", args.CDecimal); + queryParams.Add("c_double_precision", args.CDoublePrecision); + queryParams.Add("c_money", args.CMoney); + queryParams.Add("c_date", args.CDate); + queryParams.Add("c_time", args.CTime); + queryParams.Add("c_timestamp", args.CTimestamp); + queryParams.Add("c_timestamp_with_tz", args.CTimestampWithTz); + queryParams.Add("c_char", args.CChar); + queryParams.Add("c_varchar", args.CVarchar); + queryParams.Add("c_character_varying", args.CCharacterVarying); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_bytea", args.CBytea); + queryParams.Add("c_text_array", args.CTextArray); + queryParams.Add("c_integer_array", args.CIntegerArray); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertPostgresTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertPostgresTypesSql, queryParams, transaction: this.Transaction); } private const string InsertPostgresTypesBatchSql = "COPY postgres_types (c_boolean, c_smallint, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea) FROM STDIN (FORMAT BINARY)"; @@ -487,11 +709,21 @@ public class GetPostgresTypesRow }; public async Task GetPostgresTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql, transaction: this.Transaction); } private const string GetPostgresTypesCntSql = "SELECT c_smallint , c_boolean, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea, COUNT (* ) AS cnt FROM postgres_types GROUP BY c_smallint, c_boolean, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea LIMIT 1 "; @@ -519,11 +751,21 @@ public class GetPostgresTypesCntRow }; public async Task GetPostgresTypesCnt() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql, transaction: this.Transaction); } private const string GetPostgresFunctionsSql = "SELECT MAX ( c_integer ) AS max_integer , MAX (c_varchar ) AS max_varchar, MAX (c_timestamp ) AS max_timestamp FROM postgres_types "; @@ -535,11 +777,21 @@ public class GetPostgresFunctionsRow }; public async Task GetPostgresFunctions() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql, transaction: this.Transaction); } private const string InsertPostgresGeoTypesSql = "INSERT INTO postgres_geometric_types ( c_point , c_line, c_lseg, c_box, c_path, c_polygon, c_circle ) VALUES ( @c_point, @c_line, @c_lseg, @c_box, @c_path, @c_polygon, @c_circle ) "; @@ -555,18 +807,30 @@ public class InsertPostgresGeoTypesArgs }; public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_point", args.CPoint); + queryParams.Add("c_line", args.CLine); + queryParams.Add("c_lseg", args.CLseg); + queryParams.Add("c_box", args.CBox); + queryParams.Add("c_path", args.CPath); + queryParams.Add("c_polygon", args.CPolygon); + queryParams.Add("c_circle", args.CCircle); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("c_point", args.CPoint); - queryParams.Add("c_line", args.CLine); - queryParams.Add("c_lseg", args.CLseg); - queryParams.Add("c_box", args.CBox); - queryParams.Add("c_path", args.CPath); - queryParams.Add("c_polygon", args.CPolygon); - queryParams.Add("c_circle", args.CCircle); - await connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams, transaction: this.Transaction); } private const string GetPostgresGeoTypesSql = "SELECT c_point, c_line, c_lseg, c_box, c_path, c_polygon, c_circle FROM postgres_geometric_types LIMIT 1"; @@ -582,28 +846,62 @@ public class GetPostgresGeoTypesRow }; public async Task GetPostgresGeoTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql, transaction: this.Transaction); } private const string TruncatePostgresTypesSql = "TRUNCATE TABLE postgres_types"; public async Task TruncatePostgresTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(TruncatePostgresTypesSql); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncatePostgresTypesSql); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(TruncatePostgresTypesSql, transaction: this.Transaction); } private const string TruncatePostgresGeoTypesSql = "TRUNCATE TABLE postgres_geometric_types"; public async Task TruncatePostgresGeoTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncatePostgresGeoTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncatePostgresGeoTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncatePostgresGeoTypesSql, transaction: this.Transaction); } } \ No newline at end of file diff --git a/examples/NpgsqlDapperLegacyExample/QuerySql.cs b/examples/NpgsqlDapperLegacyExample/QuerySql.cs index f4e186d7..46a99015 100644 --- a/examples/NpgsqlDapperLegacyExample/QuerySql.cs +++ b/examples/NpgsqlDapperLegacyExample/QuerySql.cs @@ -23,6 +23,19 @@ public QuerySql(string connectionString) Utils.ConfigureSqlMapper(); } + private QuerySql(NpgsqlTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + Utils.ConfigureSqlMapper(); + } + + public static QuerySql WithTransaction(NpgsqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private NpgsqlTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; @@ -38,13 +51,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; @@ -56,11 +79,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio) RETURNING id, name, bio"; @@ -78,15 +111,25 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - var result = await connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio) RETURNING id"; @@ -101,13 +144,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -123,13 +176,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; @@ -145,13 +208,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; @@ -161,21 +234,45 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string TruncateAuthorsSql = "TRUNCATE TABLE authors CASCADE"; public async Task TruncateAuthors() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(TruncateAuthorsSql); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncateAuthorsSql); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(TruncateAuthorsSql, transaction: this.Transaction); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; @@ -185,12 +282,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) "; @@ -206,13 +313,23 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("longArr_1", args.LongArr1); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorsByIdsSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("longArr_1", args.LongArr1); - var result = await connection.QueryAsync(GetAuthorsByIdsSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorsByIdsSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) AND name = ANY ( @stringArr_2 :: TEXT [ ] ) "; @@ -229,14 +346,24 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("longArr_1", args.LongArr1); + queryParams.Add("stringArr_2", args.StringArr2); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("longArr_1", args.LongArr1); - queryParams.Add("stringArr_2", args.StringArr2); - var result = await connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams); - return result.AsList(); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams); + return result.AsList(); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorsByIdsAndNamesSql, queryParams, transaction: this.Transaction)).AsList(); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id) RETURNING id"; @@ -251,13 +378,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -268,20 +405,44 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -294,20 +455,44 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -326,21 +511,46 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -372,32 +582,44 @@ public class InsertPostgresTypesArgs }; public async Task InsertPostgresTypes(InsertPostgresTypesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) - { - var queryParams = new Dictionary(); - queryParams.Add("c_boolean", args.CBoolean); - queryParams.Add("c_bit", args.CBit); - queryParams.Add("c_smallint", args.CSmallint); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_bigint", args.CBigint); - queryParams.Add("c_real", args.CReal); - queryParams.Add("c_numeric", args.CNumeric); - queryParams.Add("c_decimal", args.CDecimal); - queryParams.Add("c_double_precision", args.CDoublePrecision); - queryParams.Add("c_money", args.CMoney); - queryParams.Add("c_date", args.CDate); - queryParams.Add("c_time", args.CTime); - queryParams.Add("c_timestamp", args.CTimestamp); - queryParams.Add("c_timestamp_with_tz", args.CTimestampWithTz); - queryParams.Add("c_char", args.CChar); - queryParams.Add("c_varchar", args.CVarchar); - queryParams.Add("c_character_varying", args.CCharacterVarying); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_bytea", args.CBytea); - queryParams.Add("c_text_array", args.CTextArray); - queryParams.Add("c_integer_array", args.CIntegerArray); - await connection.ExecuteAsync(InsertPostgresTypesSql, queryParams); + var queryParams = new Dictionary(); + queryParams.Add("c_boolean", args.CBoolean); + queryParams.Add("c_bit", args.CBit); + queryParams.Add("c_smallint", args.CSmallint); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_bigint", args.CBigint); + queryParams.Add("c_real", args.CReal); + queryParams.Add("c_numeric", args.CNumeric); + queryParams.Add("c_decimal", args.CDecimal); + queryParams.Add("c_double_precision", args.CDoublePrecision); + queryParams.Add("c_money", args.CMoney); + queryParams.Add("c_date", args.CDate); + queryParams.Add("c_time", args.CTime); + queryParams.Add("c_timestamp", args.CTimestamp); + queryParams.Add("c_timestamp_with_tz", args.CTimestampWithTz); + queryParams.Add("c_char", args.CChar); + queryParams.Add("c_varchar", args.CVarchar); + queryParams.Add("c_character_varying", args.CCharacterVarying); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_bytea", args.CBytea); + queryParams.Add("c_text_array", args.CTextArray); + queryParams.Add("c_integer_array", args.CIntegerArray); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertPostgresTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertPostgresTypesSql, queryParams, transaction: this.Transaction); } private const string InsertPostgresTypesBatchSql = "COPY postgres_types (c_boolean, c_smallint, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea) FROM STDIN (FORMAT BINARY)"; @@ -488,11 +710,21 @@ public class GetPostgresTypesRow }; public async Task GetPostgresTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresTypesSql, transaction: this.Transaction); } private const string GetPostgresTypesCntSql = "SELECT c_smallint , c_boolean, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea, COUNT (* ) AS cnt FROM postgres_types GROUP BY c_smallint, c_boolean, c_integer, c_bigint, c_real, c_numeric, c_decimal, c_double_precision, c_money, c_date, c_time, c_timestamp, c_timestamp_with_tz, c_char, c_varchar, c_character_varying, c_text, c_bytea LIMIT 1 "; @@ -520,11 +752,21 @@ public class GetPostgresTypesCntRow }; public async Task GetPostgresTypesCnt() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresTypesCntSql, transaction: this.Transaction); } private const string GetPostgresFunctionsSql = "SELECT MAX ( c_integer ) AS max_integer , MAX (c_varchar ) AS max_varchar, MAX (c_timestamp ) AS max_timestamp FROM postgres_types "; @@ -536,11 +778,21 @@ public class GetPostgresFunctionsRow }; public async Task GetPostgresFunctions() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql); - return result; + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresFunctionsSql, transaction: this.Transaction); } private const string InsertPostgresGeoTypesSql = "INSERT INTO postgres_geometric_types ( c_point , c_line, c_lseg, c_box, c_path, c_polygon, c_circle ) VALUES ( @c_point, @c_line, @c_lseg, @c_box, @c_path, @c_polygon, @c_circle ) "; @@ -556,18 +808,30 @@ public class InsertPostgresGeoTypesArgs }; public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) { - using (var connection = new NpgsqlConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_point", args.CPoint); + queryParams.Add("c_line", args.CLine); + queryParams.Add("c_lseg", args.CLseg); + queryParams.Add("c_box", args.CBox); + queryParams.Add("c_path", args.CPath); + queryParams.Add("c_polygon", args.CPolygon); + queryParams.Add("c_circle", args.CCircle); + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("c_point", args.CPoint); - queryParams.Add("c_line", args.CLine); - queryParams.Add("c_lseg", args.CLseg); - queryParams.Add("c_box", args.CBox); - queryParams.Add("c_path", args.CPath); - queryParams.Add("c_polygon", args.CPolygon); - queryParams.Add("c_circle", args.CCircle); - await connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(InsertPostgresGeoTypesSql, queryParams, transaction: this.Transaction); } private const string GetPostgresGeoTypesSql = "SELECT c_point, c_line, c_lseg, c_box, c_path, c_polygon, c_circle FROM postgres_geometric_types LIMIT 1"; @@ -583,29 +847,63 @@ public class GetPostgresGeoTypesRow }; public async Task GetPostgresGeoTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetPostgresGeoTypesSql, transaction: this.Transaction); } private const string TruncatePostgresTypesSql = "TRUNCATE TABLE postgres_types"; public async Task TruncatePostgresTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(TruncatePostgresTypesSql); + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncatePostgresTypesSql); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(TruncatePostgresTypesSql, transaction: this.Transaction); } private const string TruncatePostgresGeoTypesSql = "TRUNCATE TABLE postgres_geometric_types"; public async Task TruncatePostgresGeoTypes() { - using (var connection = new NpgsqlConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new NpgsqlConnection(ConnectionString)) + { + await connection.ExecuteAsync(TruncatePostgresGeoTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(TruncatePostgresGeoTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(TruncatePostgresGeoTypesSql, transaction: this.Transaction); } } } \ No newline at end of file diff --git a/examples/NpgsqlExample/QuerySql.cs b/examples/NpgsqlExample/QuerySql.cs index 80053c00..65c3f355 100644 --- a/examples/NpgsqlExample/QuerySql.cs +++ b/examples/NpgsqlExample/QuerySql.cs @@ -19,31 +19,71 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } - private string ConnectionString { get; } + private QuerySql(NpgsqlTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(NpgsqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private NpgsqlTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; public readonly record struct GetAuthorRow(long Id, string Name, string? Bio); public readonly record struct GetAuthorArgs(string Name); public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -53,20 +93,44 @@ public QuerySql(string connectionString) public readonly record struct ListAuthorsRow(long Id, string Name, string? Bio); public async Task> ListAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -76,26 +140,57 @@ public async Task> ListAuthors() public readonly record struct CreateAuthorArgs(long Id, string Name, string? Bio); public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(CreateAuthorSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - return new CreateAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new CreateAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new CreateAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -106,16 +201,34 @@ public async Task> ListAuthors() public readonly record struct CreateAuthorReturnIdArgs(string Name, string? Bio); public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateAuthorReturnIdSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt64(result); + using (var command = connection.CreateCommand(CreateAuthorReturnIdSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -123,24 +236,53 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByIdArgs(long Id); public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorByIdSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorByIdSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -151,21 +293,46 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByNamePatternArgs(string? NamePattern); public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorByNamePatternSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorByNamePatternSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -174,25 +341,60 @@ public async Task> GetAuthorByNamePattern(GetAut public readonly record struct DeleteAuthorArgs(string Name); public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(DeleteAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(DeleteAuthorSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } private const string TruncateAuthorsSql = "TRUNCATE TABLE authors CASCADE"; public async Task TruncateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncateAuthorsSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -200,14 +402,30 @@ public async Task TruncateAuthors() public readonly record struct UpdateAuthorsArgs(string? Bio); public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(UpdateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + using (var command = connection.CreateCommand(UpdateAuthorsSql)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) "; @@ -215,21 +433,46 @@ public async Task UpdateAuthors(UpdateAuthorsArgs args) public readonly record struct GetAuthorsByIdsArgs(long[] LongArr1); public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByIdsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@longArr_1", args.LongArr1); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByIdsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByIdsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -239,22 +482,48 @@ public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs public readonly record struct GetAuthorsByIdsAndNamesArgs(long[] LongArr1, string[] StringArr2); public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByIdsAndNamesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@longArr_1", args.LongArr1); - command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByIdsAndNamesSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByIdsAndNamesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -264,36 +533,78 @@ public async Task> GetAuthorsByIdsAndNames(GetA public readonly record struct CreateBookArgs(string Name, long AuthorId); public async Task CreateBook(CreateBookArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateBookSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt64(result); + using (var command = connection.CreateCommand(CreateBookSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; public readonly record struct ListAllAuthorsBooksRow(Author? Author, Book? Book); public async Task> ListAllAuthorsBooks() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -302,20 +613,44 @@ public async Task> ListAllAuthorsBooks() public readonly record struct GetDuplicateAuthorsRow(Author? Author, Author? Author2); public async Task> GetDuplicateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -325,21 +660,46 @@ public async Task> GetDuplicateAuthors() public readonly record struct GetAuthorsByBookNameArgs(string Name); public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -348,33 +708,71 @@ public async Task> GetAuthorsByBookName(GetAuthors public readonly record struct InsertPostgresTypesArgs(bool? CBoolean, byte[]? CBit, short? CSmallint, int? CInteger, long? CBigint, float? CReal, decimal? CNumeric, decimal? CDecimal, double? CDoublePrecision, decimal? CMoney, DateTime? CDate, TimeSpan? CTime, DateTime? CTimestamp, DateTime? CTimestampWithTz, string? CChar, string? CVarchar, string? CCharacterVarying, string? CText, byte[]? CBytea, string[]? CTextArray, int[]? CIntegerArray); public async Task InsertPostgresTypes(InsertPostgresTypesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) - { - using (var command = connection.CreateCommand(InsertPostgresTypesSql)) - { - command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + if (this.Transaction == null) + { + using (var connection = NpgsqlDataSource.Create(ConnectionString)) + { + using (var command = connection.CreateCommand(InsertPostgresTypesSql)) + { + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertPostgresTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -422,42 +820,89 @@ public async Task InsertPostgresTypesBatch(List ar public readonly record struct GetPostgresTypesRow(bool? CBoolean, byte[]? CBit, short? CSmallint, int? CInteger, long? CBigint, decimal? CDecimal, decimal? CNumeric, float? CReal, double? CDoublePrecision, decimal? CMoney, DateTime? CDate, TimeSpan? CTime, DateTime? CTimestamp, DateTime? CTimestampWithTz, string? CChar, string? CVarchar, string? CCharacterVarying, byte[]? CBytea, string? CText, object? CJson, string[]? CTextArray, int[]? CIntegerArray); public async Task GetPostgresTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresTypesSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresTypesRow + if (await reader.ReadAsync()) { - CBoolean = reader.IsDBNull(0) ? null : reader.GetBoolean(0), - CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), - CSmallint = reader.IsDBNull(2) ? null : reader.GetInt16(2), - CInteger = reader.IsDBNull(3) ? null : reader.GetInt32(3), - CBigint = reader.IsDBNull(4) ? null : reader.GetInt64(4), - CDecimal = reader.IsDBNull(5) ? null : reader.GetDecimal(5), - CNumeric = reader.IsDBNull(6) ? null : reader.GetDecimal(6), - CReal = reader.IsDBNull(7) ? null : reader.GetFloat(7), - CDoublePrecision = reader.IsDBNull(8) ? null : reader.GetDouble(8), - CMoney = reader.IsDBNull(9) ? null : reader.GetDecimal(9), - CDate = reader.IsDBNull(10) ? null : reader.GetDateTime(10), - CTime = reader.IsDBNull(11) ? null : reader.GetFieldValue(11), - CTimestamp = reader.IsDBNull(12) ? null : reader.GetDateTime(12), - CTimestampWithTz = reader.IsDBNull(13) ? null : reader.GetDateTime(13), - CChar = reader.IsDBNull(14) ? null : reader.GetString(14), - CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), - CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), - CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), - CText = reader.IsDBNull(18) ? null : reader.GetString(18), - CJson = reader.IsDBNull(19) ? null : reader.GetString(19), - CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), - CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) - }; + return new GetPostgresTypesRow + { + CBoolean = reader.IsDBNull(0) ? null : reader.GetBoolean(0), + CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CSmallint = reader.IsDBNull(2) ? null : reader.GetInt16(2), + CInteger = reader.IsDBNull(3) ? null : reader.GetInt32(3), + CBigint = reader.IsDBNull(4) ? null : reader.GetInt64(4), + CDecimal = reader.IsDBNull(5) ? null : reader.GetDecimal(5), + CNumeric = reader.IsDBNull(6) ? null : reader.GetDecimal(6), + CReal = reader.IsDBNull(7) ? null : reader.GetFloat(7), + CDoublePrecision = reader.IsDBNull(8) ? null : reader.GetDouble(8), + CMoney = reader.IsDBNull(9) ? null : reader.GetDecimal(9), + CDate = reader.IsDBNull(10) ? null : reader.GetDateTime(10), + CTime = reader.IsDBNull(11) ? null : reader.GetFieldValue(11), + CTimestamp = reader.IsDBNull(12) ? null : reader.GetDateTime(12), + CTimestampWithTz = reader.IsDBNull(13) ? null : reader.GetDateTime(13), + CChar = reader.IsDBNull(14) ? null : reader.GetString(14), + CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), + CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + CText = reader.IsDBNull(18) ? null : reader.GetString(18), + CJson = reader.IsDBNull(19) ? null : reader.GetString(19), + CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), + CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresTypesRow + { + CBoolean = reader.IsDBNull(0) ? null : reader.GetBoolean(0), + CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CSmallint = reader.IsDBNull(2) ? null : reader.GetInt16(2), + CInteger = reader.IsDBNull(3) ? null : reader.GetInt32(3), + CBigint = reader.IsDBNull(4) ? null : reader.GetInt64(4), + CDecimal = reader.IsDBNull(5) ? null : reader.GetDecimal(5), + CNumeric = reader.IsDBNull(6) ? null : reader.GetDecimal(6), + CReal = reader.IsDBNull(7) ? null : reader.GetFloat(7), + CDoublePrecision = reader.IsDBNull(8) ? null : reader.GetDouble(8), + CMoney = reader.IsDBNull(9) ? null : reader.GetDecimal(9), + CDate = reader.IsDBNull(10) ? null : reader.GetDateTime(10), + CTime = reader.IsDBNull(11) ? null : reader.GetFieldValue(11), + CTimestamp = reader.IsDBNull(12) ? null : reader.GetDateTime(12), + CTimestampWithTz = reader.IsDBNull(13) ? null : reader.GetDateTime(13), + CChar = reader.IsDBNull(14) ? null : reader.GetString(14), + CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), + CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + CText = reader.IsDBNull(18) ? null : reader.GetString(18), + CJson = reader.IsDBNull(19) ? null : reader.GetString(19), + CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), + CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) + }; + } + } } return null; @@ -467,39 +912,83 @@ public async Task InsertPostgresTypesBatch(List ar public readonly record struct GetPostgresTypesCntRow(short? CSmallint, bool? CBoolean, int? CInteger, long? CBigint, float? CReal, decimal? CNumeric, decimal? CDecimal, double? CDoublePrecision, decimal? CMoney, DateTime? CDate, TimeSpan? CTime, DateTime? CTimestamp, DateTime? CTimestampWithTz, string? CChar, string? CVarchar, string? CCharacterVarying, string? CText, byte[]? CBytea, long Cnt); public async Task GetPostgresTypesCnt() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresTypesCntSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresTypesCntSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresTypesCntRow + if (await reader.ReadAsync()) { - CSmallint = reader.IsDBNull(0) ? null : reader.GetInt16(0), - CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), - CInteger = reader.IsDBNull(2) ? null : reader.GetInt32(2), - CBigint = reader.IsDBNull(3) ? null : reader.GetInt64(3), - CReal = reader.IsDBNull(4) ? null : reader.GetFloat(4), - CNumeric = reader.IsDBNull(5) ? null : reader.GetDecimal(5), - CDecimal = reader.IsDBNull(6) ? null : reader.GetDecimal(6), - CDoublePrecision = reader.IsDBNull(7) ? null : reader.GetDouble(7), - CMoney = reader.IsDBNull(8) ? null : reader.GetDecimal(8), - CDate = reader.IsDBNull(9) ? null : reader.GetDateTime(9), - CTime = reader.IsDBNull(10) ? null : reader.GetFieldValue(10), - CTimestamp = reader.IsDBNull(11) ? null : reader.GetDateTime(11), - CTimestampWithTz = reader.IsDBNull(12) ? null : reader.GetDateTime(12), - CChar = reader.IsDBNull(13) ? null : reader.GetString(13), - CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), - CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), - CText = reader.IsDBNull(16) ? null : reader.GetString(16), - CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), - Cnt = reader.GetInt64(18) - }; + return new GetPostgresTypesCntRow + { + CSmallint = reader.IsDBNull(0) ? null : reader.GetInt16(0), + CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CInteger = reader.IsDBNull(2) ? null : reader.GetInt32(2), + CBigint = reader.IsDBNull(3) ? null : reader.GetInt64(3), + CReal = reader.IsDBNull(4) ? null : reader.GetFloat(4), + CNumeric = reader.IsDBNull(5) ? null : reader.GetDecimal(5), + CDecimal = reader.IsDBNull(6) ? null : reader.GetDecimal(6), + CDoublePrecision = reader.IsDBNull(7) ? null : reader.GetDouble(7), + CMoney = reader.IsDBNull(8) ? null : reader.GetDecimal(8), + CDate = reader.IsDBNull(9) ? null : reader.GetDateTime(9), + CTime = reader.IsDBNull(10) ? null : reader.GetFieldValue(10), + CTimestamp = reader.IsDBNull(11) ? null : reader.GetDateTime(11), + CTimestampWithTz = reader.IsDBNull(12) ? null : reader.GetDateTime(12), + CChar = reader.IsDBNull(13) ? null : reader.GetString(13), + CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), + CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), + CText = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + Cnt = reader.GetInt64(18) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresTypesCntRow + { + CSmallint = reader.IsDBNull(0) ? null : reader.GetInt16(0), + CBoolean = reader.IsDBNull(1) ? null : reader.GetBoolean(1), + CInteger = reader.IsDBNull(2) ? null : reader.GetInt32(2), + CBigint = reader.IsDBNull(3) ? null : reader.GetInt64(3), + CReal = reader.IsDBNull(4) ? null : reader.GetFloat(4), + CNumeric = reader.IsDBNull(5) ? null : reader.GetDecimal(5), + CDecimal = reader.IsDBNull(6) ? null : reader.GetDecimal(6), + CDoublePrecision = reader.IsDBNull(7) ? null : reader.GetDouble(7), + CMoney = reader.IsDBNull(8) ? null : reader.GetDecimal(8), + CDate = reader.IsDBNull(9) ? null : reader.GetDateTime(9), + CTime = reader.IsDBNull(10) ? null : reader.GetFieldValue(10), + CTimestamp = reader.IsDBNull(11) ? null : reader.GetDateTime(11), + CTimestampWithTz = reader.IsDBNull(12) ? null : reader.GetDateTime(12), + CChar = reader.IsDBNull(13) ? null : reader.GetString(13), + CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), + CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), + CText = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + Cnt = reader.GetInt64(18) + }; + } + } } return null; @@ -509,23 +998,51 @@ public async Task InsertPostgresTypesBatch(List ar public readonly record struct GetPostgresFunctionsRow(int? MaxInteger, string? MaxVarchar, DateTime MaxTimestamp); public async Task GetPostgresFunctions() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresFunctionsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresFunctionsSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresFunctionsRow + if (await reader.ReadAsync()) { - MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), - MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), - MaxTimestamp = reader.GetDateTime(2) - }; + return new GetPostgresFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2) + }; + } + } } return null; @@ -535,19 +1052,43 @@ public async Task InsertPostgresTypesBatch(List ar public readonly record struct InsertPostgresGeoTypesArgs(NpgsqlPoint? CPoint, NpgsqlLine? CLine, NpgsqlLSeg? CLseg, NpgsqlBox? CBox, NpgsqlPath? CPath, NpgsqlPolygon? CPolygon, NpgsqlCircle? CCircle); public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(InsertPostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(InsertPostgresGeoTypesSql)) + { + command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertPostgresGeoTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -555,27 +1096,59 @@ public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) public readonly record struct GetPostgresGeoTypesRow(NpgsqlPoint? CPoint, NpgsqlLine? CLine, NpgsqlLSeg? CLseg, NpgsqlBox? CBox, NpgsqlPath? CPath, NpgsqlPolygon? CPolygon, NpgsqlCircle? CCircle); public async Task GetPostgresGeoTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresGeoTypesSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresGeoTypesRow + if (await reader.ReadAsync()) { - CPoint = reader.IsDBNull(0) ? null : reader.GetFieldValue(0), - CLine = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), - CLseg = reader.IsDBNull(2) ? null : reader.GetFieldValue(2), - CBox = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), - CPath = reader.IsDBNull(4) ? null : reader.GetFieldValue(4), - CPolygon = reader.IsDBNull(5) ? null : reader.GetFieldValue(5), - CCircle = reader.IsDBNull(6) ? null : reader.GetFieldValue(6) - }; + return new GetPostgresGeoTypesRow + { + CPoint = reader.IsDBNull(0) ? null : reader.GetFieldValue(0), + CLine = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CLseg = reader.IsDBNull(2) ? null : reader.GetFieldValue(2), + CBox = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + CPath = reader.IsDBNull(4) ? null : reader.GetFieldValue(4), + CPolygon = reader.IsDBNull(5) ? null : reader.GetFieldValue(5), + CCircle = reader.IsDBNull(6) ? null : reader.GetFieldValue(6) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresGeoTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresGeoTypesRow + { + CPoint = reader.IsDBNull(0) ? null : reader.GetFieldValue(0), + CLine = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CLseg = reader.IsDBNull(2) ? null : reader.GetFieldValue(2), + CBox = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + CPath = reader.IsDBNull(4) ? null : reader.GetFieldValue(4), + CPolygon = reader.IsDBNull(5) ? null : reader.GetFieldValue(5), + CCircle = reader.IsDBNull(6) ? null : reader.GetFieldValue(6) + }; + } + } } return null; @@ -584,24 +1157,58 @@ public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) private const string TruncatePostgresTypesSql = "TRUNCATE TABLE postgres_types"; public async Task TruncatePostgresTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncatePostgresTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncatePostgresTypesSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncatePostgresTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } private const string TruncatePostgresGeoTypesSql = "TRUNCATE TABLE postgres_geometric_types"; public async Task TruncatePostgresGeoTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncatePostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncatePostgresGeoTypesSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncatePostgresGeoTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } } \ No newline at end of file diff --git a/examples/NpgsqlLegacyExample/QuerySql.cs b/examples/NpgsqlLegacyExample/QuerySql.cs index 8097ad0f..5344de2c 100644 --- a/examples/NpgsqlLegacyExample/QuerySql.cs +++ b/examples/NpgsqlLegacyExample/QuerySql.cs @@ -20,6 +20,17 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } + private QuerySql(NpgsqlTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(NpgsqlTransaction transaction) + { + return new QuerySql(transaction); + } + + private NpgsqlTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; @@ -35,24 +46,53 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -67,20 +107,44 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -100,26 +164,57 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(CreateAuthorSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - return new CreateAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new CreateAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new CreateAuthorRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -137,16 +232,34 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateAuthorReturnIdSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt64(result); + using (var command = connection.CreateCommand(CreateAuthorReturnIdSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -162,24 +275,53 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorByIdSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorByIdSql)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt64(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt64(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -198,21 +340,46 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorByNamePatternSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorByNamePatternSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -224,25 +391,60 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(DeleteAuthorSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(DeleteAuthorSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } private const string TruncateAuthorsSql = "TRUNCATE TABLE authors CASCADE"; public async Task TruncateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncateAuthorsSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncateAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -253,14 +455,30 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(UpdateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + using (var command = connection.CreateCommand(UpdateAuthorsSql)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id = ANY ( @longArr_1 :: BIGINT [ ] ) "; @@ -276,21 +494,46 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByIdsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@longArr_1", args.LongArr1); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByIdsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByIdsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -309,22 +552,48 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByIdsAndNamesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@longArr_1", args.LongArr1); - command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByIdsAndNamesSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByIdsAndNamesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@longArr_1", args.LongArr1); + command.Parameters.AddWithValue("@stringArr_2", args.StringArr2); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -341,16 +610,34 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(CreateBookSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt64(result); + using (var command = connection.CreateCommand(CreateBookSql)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt64(result); + } } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -361,20 +648,44 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(ListAllAuthorsBooksSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -387,20 +698,44 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetDuplicateAuthorsSql)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt64(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -419,21 +754,46 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetAuthorsByBookNameSql)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt64(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt64(3), Name = reader.GetString(4), AuthorId = reader.GetInt64(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -465,33 +825,71 @@ public class InsertPostgresTypesArgs }; public async Task InsertPostgresTypes(InsertPostgresTypesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) - { - using (var command = connection.CreateCommand(InsertPostgresTypesSql)) - { - command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + if (this.Transaction == null) + { + using (var connection = NpgsqlDataSource.Create(ConnectionString)) + { + using (var command = connection.CreateCommand(InsertPostgresTypesSql)) + { + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertPostgresTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_boolean", args.CBoolean ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bit", args.CBit ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_smallint", args.CSmallint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bigint", args.CBigint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_numeric", args.CNumeric ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_decimal", args.CDecimal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_double_precision", args.CDoublePrecision ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_money", args.CMoney ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_date", args.CDate ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_time", args.CTime ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp", args.CTimestamp ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_timestamp_with_tz", args.CTimestampWithTz ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_char", args.CChar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_varchar", args.CVarchar ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_character_varying", args.CCharacterVarying ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_bytea", args.CBytea ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text_array", args.CTextArray ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_integer_array", args.CIntegerArray ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -583,42 +981,89 @@ public class GetPostgresTypesRow }; public async Task GetPostgresTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresTypesSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresTypesRow + if (await reader.ReadAsync()) { - CBoolean = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), - CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), - CSmallint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), - CInteger = reader.IsDBNull(3) ? (int? )null : reader.GetInt32(3), - CBigint = reader.IsDBNull(4) ? (long? )null : reader.GetInt64(4), - CDecimal = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), - CNumeric = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), - CReal = reader.IsDBNull(7) ? (float? )null : reader.GetFloat(7), - CDoublePrecision = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), - CMoney = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), - CDate = reader.IsDBNull(10) ? (DateTime? )null : reader.GetDateTime(10), - CTime = reader.IsDBNull(11) ? (TimeSpan? )null : reader.GetFieldValue(11), - CTimestamp = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), - CTimestampWithTz = reader.IsDBNull(13) ? (DateTime? )null : reader.GetDateTime(13), - CChar = reader.IsDBNull(14) ? null : reader.GetString(14), - CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), - CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), - CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), - CText = reader.IsDBNull(18) ? null : reader.GetString(18), - CJson = reader.IsDBNull(19) ? null : reader.GetString(19), - CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), - CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) - }; + return new GetPostgresTypesRow + { + CBoolean = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), + CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CSmallint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), + CInteger = reader.IsDBNull(3) ? (int? )null : reader.GetInt32(3), + CBigint = reader.IsDBNull(4) ? (long? )null : reader.GetInt64(4), + CDecimal = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), + CNumeric = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), + CReal = reader.IsDBNull(7) ? (float? )null : reader.GetFloat(7), + CDoublePrecision = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), + CMoney = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), + CDate = reader.IsDBNull(10) ? (DateTime? )null : reader.GetDateTime(10), + CTime = reader.IsDBNull(11) ? (TimeSpan? )null : reader.GetFieldValue(11), + CTimestamp = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), + CTimestampWithTz = reader.IsDBNull(13) ? (DateTime? )null : reader.GetDateTime(13), + CChar = reader.IsDBNull(14) ? null : reader.GetString(14), + CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), + CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + CText = reader.IsDBNull(18) ? null : reader.GetString(18), + CJson = reader.IsDBNull(19) ? null : reader.GetString(19), + CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), + CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresTypesRow + { + CBoolean = reader.IsDBNull(0) ? (bool? )null : reader.GetBoolean(0), + CBit = reader.IsDBNull(1) ? null : reader.GetFieldValue(1), + CSmallint = reader.IsDBNull(2) ? (short? )null : reader.GetInt16(2), + CInteger = reader.IsDBNull(3) ? (int? )null : reader.GetInt32(3), + CBigint = reader.IsDBNull(4) ? (long? )null : reader.GetInt64(4), + CDecimal = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), + CNumeric = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), + CReal = reader.IsDBNull(7) ? (float? )null : reader.GetFloat(7), + CDoublePrecision = reader.IsDBNull(8) ? (double? )null : reader.GetDouble(8), + CMoney = reader.IsDBNull(9) ? (decimal? )null : reader.GetDecimal(9), + CDate = reader.IsDBNull(10) ? (DateTime? )null : reader.GetDateTime(10), + CTime = reader.IsDBNull(11) ? (TimeSpan? )null : reader.GetFieldValue(11), + CTimestamp = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), + CTimestampWithTz = reader.IsDBNull(13) ? (DateTime? )null : reader.GetDateTime(13), + CChar = reader.IsDBNull(14) ? null : reader.GetString(14), + CVarchar = reader.IsDBNull(15) ? null : reader.GetString(15), + CCharacterVarying = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + CText = reader.IsDBNull(18) ? null : reader.GetString(18), + CJson = reader.IsDBNull(19) ? null : reader.GetString(19), + CTextArray = reader.IsDBNull(20) ? null : reader.GetFieldValue(20), + CIntegerArray = reader.IsDBNull(21) ? null : reader.GetFieldValue(21) + }; + } + } } return null; @@ -649,39 +1094,83 @@ public class GetPostgresTypesCntRow }; public async Task GetPostgresTypesCnt() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresTypesCntSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresTypesCntSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresTypesCntRow + if (await reader.ReadAsync()) { - CSmallint = reader.IsDBNull(0) ? (short? )null : reader.GetInt16(0), - CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), - CInteger = reader.IsDBNull(2) ? (int? )null : reader.GetInt32(2), - CBigint = reader.IsDBNull(3) ? (long? )null : reader.GetInt64(3), - CReal = reader.IsDBNull(4) ? (float? )null : reader.GetFloat(4), - CNumeric = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), - CDecimal = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), - CDoublePrecision = reader.IsDBNull(7) ? (double? )null : reader.GetDouble(7), - CMoney = reader.IsDBNull(8) ? (decimal? )null : reader.GetDecimal(8), - CDate = reader.IsDBNull(9) ? (DateTime? )null : reader.GetDateTime(9), - CTime = reader.IsDBNull(10) ? (TimeSpan? )null : reader.GetFieldValue(10), - CTimestamp = reader.IsDBNull(11) ? (DateTime? )null : reader.GetDateTime(11), - CTimestampWithTz = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), - CChar = reader.IsDBNull(13) ? null : reader.GetString(13), - CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), - CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), - CText = reader.IsDBNull(16) ? null : reader.GetString(16), - CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), - Cnt = reader.GetInt64(18) - }; + return new GetPostgresTypesCntRow + { + CSmallint = reader.IsDBNull(0) ? (short? )null : reader.GetInt16(0), + CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CInteger = reader.IsDBNull(2) ? (int? )null : reader.GetInt32(2), + CBigint = reader.IsDBNull(3) ? (long? )null : reader.GetInt64(3), + CReal = reader.IsDBNull(4) ? (float? )null : reader.GetFloat(4), + CNumeric = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), + CDecimal = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), + CDoublePrecision = reader.IsDBNull(7) ? (double? )null : reader.GetDouble(7), + CMoney = reader.IsDBNull(8) ? (decimal? )null : reader.GetDecimal(8), + CDate = reader.IsDBNull(9) ? (DateTime? )null : reader.GetDateTime(9), + CTime = reader.IsDBNull(10) ? (TimeSpan? )null : reader.GetFieldValue(10), + CTimestamp = reader.IsDBNull(11) ? (DateTime? )null : reader.GetDateTime(11), + CTimestampWithTz = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), + CChar = reader.IsDBNull(13) ? null : reader.GetString(13), + CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), + CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), + CText = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + Cnt = reader.GetInt64(18) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresTypesCntRow + { + CSmallint = reader.IsDBNull(0) ? (short? )null : reader.GetInt16(0), + CBoolean = reader.IsDBNull(1) ? (bool? )null : reader.GetBoolean(1), + CInteger = reader.IsDBNull(2) ? (int? )null : reader.GetInt32(2), + CBigint = reader.IsDBNull(3) ? (long? )null : reader.GetInt64(3), + CReal = reader.IsDBNull(4) ? (float? )null : reader.GetFloat(4), + CNumeric = reader.IsDBNull(5) ? (decimal? )null : reader.GetDecimal(5), + CDecimal = reader.IsDBNull(6) ? (decimal? )null : reader.GetDecimal(6), + CDoublePrecision = reader.IsDBNull(7) ? (double? )null : reader.GetDouble(7), + CMoney = reader.IsDBNull(8) ? (decimal? )null : reader.GetDecimal(8), + CDate = reader.IsDBNull(9) ? (DateTime? )null : reader.GetDateTime(9), + CTime = reader.IsDBNull(10) ? (TimeSpan? )null : reader.GetFieldValue(10), + CTimestamp = reader.IsDBNull(11) ? (DateTime? )null : reader.GetDateTime(11), + CTimestampWithTz = reader.IsDBNull(12) ? (DateTime? )null : reader.GetDateTime(12), + CChar = reader.IsDBNull(13) ? null : reader.GetString(13), + CVarchar = reader.IsDBNull(14) ? null : reader.GetString(14), + CCharacterVarying = reader.IsDBNull(15) ? null : reader.GetString(15), + CText = reader.IsDBNull(16) ? null : reader.GetString(16), + CBytea = reader.IsDBNull(17) ? null : reader.GetFieldValue(17), + Cnt = reader.GetInt64(18) + }; + } + } } return null; @@ -696,23 +1185,51 @@ public class GetPostgresFunctionsRow }; public async Task GetPostgresFunctions() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresFunctionsSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresFunctionsSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresFunctionsRow + if (await reader.ReadAsync()) { - MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), - MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), - MaxTimestamp = reader.GetDateTime(2) - }; + return new GetPostgresFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxVarchar = reader.IsDBNull(1) ? null : reader.GetString(1), + MaxTimestamp = reader.GetDateTime(2) + }; + } + } } return null; @@ -731,19 +1248,43 @@ public class InsertPostgresGeoTypesArgs }; public async Task InsertPostgresGeoTypes(InsertPostgresGeoTypesArgs args) { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(InsertPostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(InsertPostgresGeoTypesSql)) + { + command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertPostgresGeoTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_point", args.CPoint ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_line", args.CLine ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_lseg", args.CLseg ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_box", args.CBox ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_path", args.CPath ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_polygon", args.CPolygon ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_circle", args.CCircle ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -760,27 +1301,59 @@ public class GetPostgresGeoTypesRow }; public async Task GetPostgresGeoTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(GetPostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + using (var command = connection.CreateCommand(GetPostgresGeoTypesSql)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetPostgresGeoTypesRow + if (await reader.ReadAsync()) { - CPoint = reader.IsDBNull(0) ? (NpgsqlPoint? )null : reader.GetFieldValue(0), - CLine = reader.IsDBNull(1) ? (NpgsqlLine? )null : reader.GetFieldValue(1), - CLseg = reader.IsDBNull(2) ? (NpgsqlLSeg? )null : reader.GetFieldValue(2), - CBox = reader.IsDBNull(3) ? (NpgsqlBox? )null : reader.GetFieldValue(3), - CPath = reader.IsDBNull(4) ? (NpgsqlPath? )null : reader.GetFieldValue(4), - CPolygon = reader.IsDBNull(5) ? (NpgsqlPolygon? )null : reader.GetFieldValue(5), - CCircle = reader.IsDBNull(6) ? (NpgsqlCircle? )null : reader.GetFieldValue(6) - }; + return new GetPostgresGeoTypesRow + { + CPoint = reader.IsDBNull(0) ? (NpgsqlPoint? )null : reader.GetFieldValue(0), + CLine = reader.IsDBNull(1) ? (NpgsqlLine? )null : reader.GetFieldValue(1), + CLseg = reader.IsDBNull(2) ? (NpgsqlLSeg? )null : reader.GetFieldValue(2), + CBox = reader.IsDBNull(3) ? (NpgsqlBox? )null : reader.GetFieldValue(3), + CPath = reader.IsDBNull(4) ? (NpgsqlPath? )null : reader.GetFieldValue(4), + CPolygon = reader.IsDBNull(5) ? (NpgsqlPolygon? )null : reader.GetFieldValue(5), + CCircle = reader.IsDBNull(6) ? (NpgsqlCircle? )null : reader.GetFieldValue(6) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetPostgresGeoTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetPostgresGeoTypesRow + { + CPoint = reader.IsDBNull(0) ? (NpgsqlPoint? )null : reader.GetFieldValue(0), + CLine = reader.IsDBNull(1) ? (NpgsqlLine? )null : reader.GetFieldValue(1), + CLseg = reader.IsDBNull(2) ? (NpgsqlLSeg? )null : reader.GetFieldValue(2), + CBox = reader.IsDBNull(3) ? (NpgsqlBox? )null : reader.GetFieldValue(3), + CPath = reader.IsDBNull(4) ? (NpgsqlPath? )null : reader.GetFieldValue(4), + CPolygon = reader.IsDBNull(5) ? (NpgsqlPolygon? )null : reader.GetFieldValue(5), + CCircle = reader.IsDBNull(6) ? (NpgsqlCircle? )null : reader.GetFieldValue(6) + }; + } + } } return null; @@ -789,24 +1362,58 @@ public async Task GetPostgresGeoTypes() private const string TruncatePostgresTypesSql = "TRUNCATE TABLE postgres_types"; public async Task TruncatePostgresTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncatePostgresTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncatePostgresTypesSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncatePostgresTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } private const string TruncatePostgresGeoTypesSql = "TRUNCATE TABLE postgres_geometric_types"; public async Task TruncatePostgresGeoTypes() { - using (var connection = NpgsqlDataSource.Create(ConnectionString)) + if (this.Transaction == null) { - using (var command = connection.CreateCommand(TruncatePostgresGeoTypesSql)) + using (var connection = NpgsqlDataSource.Create(ConnectionString)) { - await command.ExecuteScalarAsync(); + using (var command = connection.CreateCommand(TruncatePostgresGeoTypesSql)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = TruncatePostgresGeoTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } } diff --git a/examples/SqliteDapperExample/QuerySql.cs b/examples/SqliteDapperExample/QuerySql.cs index b0cc960e..fd122ba8 100644 --- a/examples/SqliteDapperExample/QuerySql.cs +++ b/examples/SqliteDapperExample/QuerySql.cs @@ -19,7 +19,19 @@ public QuerySql(string connectionString) Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; } - private string ConnectionString { get; } + private QuerySql(SqliteTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + } + + public static QuerySql WithTransaction(SqliteTransaction transaction) + { + return new QuerySql(transaction); + } + + private SqliteTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; public class GetAuthorRow @@ -34,13 +46,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; @@ -52,11 +74,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; @@ -68,14 +100,26 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - await connection.ExecuteAsync(CreateAuthorSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateAuthorSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio) RETURNING id"; @@ -90,13 +134,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -112,13 +166,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; @@ -134,13 +198,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; @@ -150,12 +224,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -171,16 +255,26 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names)"; @@ -197,19 +291,29 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + queryParams.Add($"@namesArg{i}", args.Names[i]); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - queryParams.Add($"@namesArg{i}", args.Names[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; @@ -219,12 +323,24 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id) RETURNING id"; @@ -239,13 +355,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -256,21 +382,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -283,21 +433,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -316,22 +490,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -339,10 +538,22 @@ public async Task> GetAuthorsByBookName(GetAuthors private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(DeleteAllAuthorsSql); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllAuthorsSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } private const string InsertSqliteTypesSql = "INSERT INTO types_sqlite (c_integer, c_real, c_text, c_blob) VALUES ( @c_integer , @c_real, @c_text, @c_blob ) "; @@ -355,15 +566,27 @@ public class InsertSqliteTypesArgs }; public async Task InsertSqliteTypes(InsertSqliteTypesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_real", args.CReal); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_blob", args.CBlob); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_real", args.CReal); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_blob", args.CBlob); - await connection.ExecuteAsync(InsertSqliteTypesSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertSqliteTypesSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(InsertSqliteTypesSql, queryParams, transaction: this.Transaction); } private const string InsertSqliteTypesBatchSql = "INSERT INTO types_sqlite (c_integer, c_real, c_text) VALUES (@c_integer, @c_real, @c_text)"; @@ -403,11 +626,21 @@ public class GetSqliteTypesRow }; public async Task GetSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql, transaction: this.Transaction); } private const string GetSqliteTypesCntSql = "SELECT c_integer , c_real, c_text, c_blob, COUNT (* ) AS cnt FROM types_sqlite GROUP BY c_integer, c_real, c_text, c_blob LIMIT 1 "; @@ -421,11 +654,21 @@ public class GetSqliteTypesCntRow }; public async Task GetSqliteTypesCnt() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql); - return result; + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql, transaction: this.Transaction); } private const string GetSqliteFunctionsSql = "SELECT MAX ( c_integer ) AS max_integer , MAX (c_real ) AS max_real, MAX (c_text ) AS max_text FROM types_sqlite "; @@ -437,19 +680,41 @@ public class GetSqliteFunctionsRow }; public async Task GetSqliteFunctions() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql); - return result; + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql, transaction: this.Transaction); } private const string DeleteAllSqliteTypesSql = "DELETE FROM types_sqlite"; public async Task DeleteAllSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllSqliteTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(DeleteAllSqliteTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllSqliteTypesSql, transaction: this.Transaction); } } \ No newline at end of file diff --git a/examples/SqliteDapperLegacyExample/QuerySql.cs b/examples/SqliteDapperLegacyExample/QuerySql.cs index cbb5f959..bdd92601 100644 --- a/examples/SqliteDapperLegacyExample/QuerySql.cs +++ b/examples/SqliteDapperLegacyExample/QuerySql.cs @@ -20,6 +20,18 @@ public QuerySql(string connectionString) Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; } + private QuerySql(SqliteTransaction transaction) + { + this.Transaction = transaction; + Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; + } + + public static QuerySql WithTransaction(SqliteTransaction transaction) + { + return new QuerySql(transaction); + } + + private SqliteTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; @@ -35,13 +47,23 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorSql, queryParams, transaction: this.Transaction); } private const string ListAuthorsSql = "SELECT id, name, bio FROM authors ORDER BY name "; @@ -53,11 +75,21 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryAsync(ListAuthorsSql); - return result.AsList(); + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(ListAuthorsSql); + return result.AsList(); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return (await this.Transaction.Connection.QueryAsync(ListAuthorsSql, transaction: this.Transaction)).AsList(); } private const string CreateAuthorSql = "INSERT INTO authors (id, name, bio) VALUES (@id, @name, @bio)"; @@ -69,14 +101,26 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - await connection.ExecuteAsync(CreateAuthorSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(CreateAuthorSql, queryParams); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(CreateAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateAuthorReturnIdSql = "INSERT INTO authors (name, bio) VALUES (@name, @bio) RETURNING id"; @@ -91,13 +135,23 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("bio", args.Bio); - return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QuerySingleAsync(CreateAuthorReturnIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -113,13 +167,23 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("id", args.Id); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("id", args.Id); - var result = await connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetAuthorByIdSql, queryParams, transaction: this.Transaction); } private const string GetAuthorByNamePatternSql = "SELECT id, name, bio FROM authors WHERE name LIKE COALESCE ( @name_pattern , '%' ) "; @@ -135,13 +199,23 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name_pattern", args.NamePattern); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name_pattern", args.NamePattern); - var result = await connection.QueryAsync(GetAuthorByNamePatternSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(GetAuthorByNamePatternSql, queryParams, transaction: this.Transaction)).AsList(); } private const string UpdateAuthorsSql = "UPDATE authors SET bio = @bio WHERE bio IS NOT NULL "; @@ -151,12 +225,22 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("bio", args.Bio); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("bio", args.Bio); - return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.ExecuteAsync(UpdateAuthorsSql, queryParams); + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.ExecuteAsync(UpdateAuthorsSql, queryParams, transaction: this.Transaction); } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -172,16 +256,26 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string GetAuthorsByIdsAndNamesSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids) AND name IN (/*SLICE:names*/@names)"; @@ -198,19 +292,29 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + var queryParams = new Dictionary(); + for (int i = 0; i < args.Ids.Length; i++) + queryParams.Add($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + queryParams.Add($"@namesArg{i}", args.Names[i]); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryAsync(transformedSql, queryParams); + return result.AsList(); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - var queryParams = new Dictionary(); - for (int i = 0; i < args.Ids.Length; i++) - queryParams.Add($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - queryParams.Add($"@namesArg{i}", args.Names[i]); - var result = await connection.QueryAsync(transformedSql, queryParams); - return result.AsList(); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return (await this.Transaction.Connection.QueryAsync(transformedSql, queryParams, transaction: this.Transaction)).AsList(); } private const string DeleteAuthorSql = "DELETE FROM authors WHERE name = @name "; @@ -220,12 +324,24 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAuthorSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(DeleteAuthorSql, queryParams, transaction: this.Transaction); } private const string CreateBookSql = "INSERT INTO books (name, author_id) VALUES (@name, @author_id) RETURNING id"; @@ -240,13 +356,23 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("name", args.Name); + queryParams.Add("author_id", args.AuthorId); + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + return await connection.QuerySingleAsync(CreateBookSql, queryParams); + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var queryParams = new Dictionary(); - queryParams.Add("name", args.Name); - queryParams.Add("author_id", args.AuthorId); - return await connection.QuerySingleAsync(CreateBookSql, queryParams); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QuerySingleAsync(CreateBookSql, queryParams, transaction: this.Transaction); } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -257,21 +383,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -284,21 +434,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -317,22 +491,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -340,10 +539,22 @@ public async Task> GetAuthorsByBookName(GetAuthors private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.ExecuteAsync(DeleteAllAuthorsSql); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllAuthorsSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllAuthorsSql, transaction: this.Transaction); } private const string InsertSqliteTypesSql = "INSERT INTO types_sqlite (c_integer, c_real, c_text, c_blob) VALUES ( @c_integer , @c_real, @c_text, @c_blob ) "; @@ -356,15 +567,27 @@ public class InsertSqliteTypesArgs }; public async Task InsertSqliteTypes(InsertSqliteTypesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var queryParams = new Dictionary(); + queryParams.Add("c_integer", args.CInteger); + queryParams.Add("c_real", args.CReal); + queryParams.Add("c_text", args.CText); + queryParams.Add("c_blob", args.CBlob); + if (this.Transaction == null) { - var queryParams = new Dictionary(); - queryParams.Add("c_integer", args.CInteger); - queryParams.Add("c_real", args.CReal); - queryParams.Add("c_text", args.CText); - queryParams.Add("c_blob", args.CBlob); - await connection.ExecuteAsync(InsertSqliteTypesSql, queryParams); + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(InsertSqliteTypesSql, queryParams); + } + + return; } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + await this.Transaction.Connection.ExecuteAsync(InsertSqliteTypesSql, queryParams, transaction: this.Transaction); } private const string InsertSqliteTypesBatchSql = "INSERT INTO types_sqlite (c_integer, c_real, c_text) VALUES (@c_integer, @c_real, @c_text)"; @@ -404,11 +627,21 @@ public class GetSqliteTypesRow }; public async Task GetSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql); - return result; + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteTypesSql, transaction: this.Transaction); } private const string GetSqliteTypesCntSql = "SELECT c_integer , c_real, c_text, c_blob, COUNT (* ) AS cnt FROM types_sqlite GROUP BY c_integer, c_real, c_text, c_blob LIMIT 1 "; @@ -422,11 +655,21 @@ public class GetSqliteTypesCntRow }; public async Task GetSqliteTypesCnt() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql); - return result; + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql); + return result; + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteTypesCntSql, transaction: this.Transaction); } private const string GetSqliteFunctionsSql = "SELECT MAX ( c_integer ) AS max_integer , MAX (c_real ) AS max_real, MAX (c_text ) AS max_text FROM types_sqlite "; @@ -438,20 +681,42 @@ public class GetSqliteFunctionsRow }; public async Task GetSqliteFunctions() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - var result = await connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql); - return result; + using (var connection = new SqliteConnection(ConnectionString)) + { + var result = await connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql); + return result; + } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + return await this.Transaction.Connection.QueryFirstOrDefaultAsync(GetSqliteFunctionsSql, transaction: this.Transaction); } private const string DeleteAllSqliteTypesSql = "DELETE FROM types_sqlite"; public async Task DeleteAllSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) + { + using (var connection = new SqliteConnection(ConnectionString)) + { + await connection.ExecuteAsync(DeleteAllSqliteTypesSql); + } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) { - await connection.ExecuteAsync(DeleteAllSqliteTypesSql); + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); } + + await this.Transaction.Connection.ExecuteAsync(DeleteAllSqliteTypesSql, transaction: this.Transaction); } } } \ No newline at end of file diff --git a/examples/SqliteExample/QuerySql.cs b/examples/SqliteExample/QuerySql.cs index fdf44081..5ef332d4 100644 --- a/examples/SqliteExample/QuerySql.cs +++ b/examples/SqliteExample/QuerySql.cs @@ -17,32 +17,72 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } - private string ConnectionString { get; } + private QuerySql(SqliteTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(SqliteTransaction transaction) + { + return new QuerySql(transaction); + } + + private SqliteTransaction? Transaction { get; } + private string? ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; public readonly record struct GetAuthorRow(int Id, string Name, string? Bio); public readonly record struct GetAuthorArgs(string Name); public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt32(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -52,21 +92,45 @@ public QuerySql(string connectionString) public readonly record struct ListAuthorsRow(int Id, string Name, string? Bio); public async Task> ListAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -75,16 +139,36 @@ public async Task> ListAuthors() public readonly record struct CreateAuthorArgs(int Id, string Name, string? Bio); public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateAuthorSql, connection)) + { + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -93,17 +177,35 @@ public async Task CreateAuthor(CreateAuthorArgs args) public readonly record struct CreateAuthorReturnIdArgs(string Name, string? Bio); public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateAuthorReturnIdSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt32(result); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateAuthorReturnIdSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -111,25 +213,54 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByIdArgs(int Id); public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorByIdSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorByIdSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt32(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -140,22 +271,47 @@ public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) public readonly record struct GetAuthorByNamePatternArgs(string? NamePattern); public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorByNamePatternSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorByNamePatternSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -164,15 +320,31 @@ public async Task> GetAuthorByNamePattern(GetAut public readonly record struct UpdateAuthorsArgs(string? Bio); public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(UpdateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(UpdateAuthorsSql, connection)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -180,25 +352,51 @@ public async Task UpdateAuthors(UpdateAuthorsArgs args) public readonly record struct GetAuthorsByIdsArgs(int[] Ids); public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - using (var command = new SqliteCommand(transformedSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -208,28 +406,56 @@ public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs public readonly record struct GetAuthorsByIdsAndNamesArgs(int[] Ids, string[] Names); public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - using (var command = new SqliteCommand(transformedSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -238,14 +464,32 @@ public async Task> GetAuthorsByIdsAndNames(GetA public readonly record struct DeleteAuthorArgs(string Name); public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAuthorSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } @@ -254,38 +498,80 @@ public async Task DeleteAuthor(DeleteAuthorArgs args) public readonly record struct CreateBookArgs(string Name, int AuthorId); public async Task CreateBook(CreateBookArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateBookSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt32(result); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateBookSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; public readonly record struct ListAllAuthorsBooksRow(Author? Author, Book? Book); public async Task> ListAllAuthorsBooks() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -294,21 +580,45 @@ public async Task> ListAllAuthorsBooks() public readonly record struct GetDuplicateAuthorsRow(Author? Author, Author? Author2); public async Task> GetDuplicateAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -318,22 +628,47 @@ public async Task> GetDuplicateAuthors() public readonly record struct GetAuthorsByBookNameArgs(string Name); public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -341,13 +676,30 @@ public async Task> GetAuthorsByBookName(GetAuthors private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAllAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAllAuthorsSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -355,17 +707,38 @@ public async Task DeleteAllAuthors() public readonly record struct InsertSqliteTypesArgs(int? CInteger, decimal? CReal, string? CText, byte[]? CBlob); public async Task InsertSqliteTypes(InsertSqliteTypesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(InsertSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(InsertSqliteTypesSql, connection)) + { + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertSqliteTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -395,25 +768,54 @@ public async Task InsertSqliteTypesBatch(List args) public readonly record struct GetSqliteTypesRow(int? CInteger, decimal? CReal, string? CText, byte[]? CBlob); public async Task GetSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteTypesSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteTypesRow + if (await reader.ReadAsync()) { - CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), - CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), - CText = reader.IsDBNull(2) ? null : reader.GetString(2), - CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) - }; + return new GetSqliteTypesRow + { + CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteTypesRow + { + CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) + }; + } + } } return null; @@ -423,26 +825,56 @@ public async Task InsertSqliteTypesBatch(List args) public readonly record struct GetSqliteTypesCntRow(int? CInteger, decimal? CReal, string? CText, byte[]? CBlob, int Cnt); public async Task GetSqliteTypesCnt() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteTypesCntSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteTypesCntSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteTypesCntRow + if (await reader.ReadAsync()) { - CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), - CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), - CText = reader.IsDBNull(2) ? null : reader.GetString(2), - CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), - Cnt = reader.GetInt32(4) - }; + return new GetSqliteTypesCntRow + { + CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + Cnt = reader.GetInt32(4) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteTypesCntRow + { + CInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + Cnt = reader.GetInt32(4) + }; + } + } } return null; @@ -452,24 +884,52 @@ public async Task InsertSqliteTypesBatch(List args) public readonly record struct GetSqliteFunctionsRow(int? MaxInteger, decimal MaxReal, object? MaxText); public async Task GetSqliteFunctions() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteFunctionsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteFunctionsSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteFunctionsRow + if (await reader.ReadAsync()) { - MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), - MaxReal = reader.GetDecimal(1), - MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) - }; + return new GetSqliteFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxReal = reader.GetDecimal(1), + MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? null : reader.GetInt32(0), + MaxReal = reader.GetDecimal(1), + MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) + }; + } + } } return null; @@ -478,13 +938,30 @@ public async Task InsertSqliteTypesBatch(List args) private const string DeleteAllSqliteTypesSql = "DELETE FROM types_sqlite"; public async Task DeleteAllSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAllSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAllSqliteTypesSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllSqliteTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } } \ No newline at end of file diff --git a/examples/SqliteLegacyExample/QuerySql.cs b/examples/SqliteLegacyExample/QuerySql.cs index fc5f16c4..a2ff5900 100644 --- a/examples/SqliteLegacyExample/QuerySql.cs +++ b/examples/SqliteLegacyExample/QuerySql.cs @@ -18,6 +18,17 @@ public QuerySql(string connectionString) this.ConnectionString = connectionString; } + private QuerySql(SqliteTransaction transaction) + { + this.Transaction = transaction; + } + + public static QuerySql WithTransaction(SqliteTransaction transaction) + { + return new QuerySql(transaction); + } + + private SqliteTransaction Transaction { get; } private string ConnectionString { get; } private const string GetAuthorSql = "SELECT id, name, bio FROM authors WHERE name = @name LIMIT 1 "; @@ -33,25 +44,54 @@ public class GetAuthorArgs }; public async Task GetAuthor(GetAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorRow + if (await reader.ReadAsync()) { - Id = reader.GetInt32(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -66,21 +106,45 @@ public class ListAuthorsRow }; public async Task> ListAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAuthorsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -94,16 +158,36 @@ public class CreateAuthorArgs }; public async Task CreateAuthor(CreateAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateAuthorSql, connection)) + { + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -119,17 +203,35 @@ public class CreateAuthorReturnIdArgs }; public async Task CreateAuthorReturnId(CreateAuthorReturnIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateAuthorReturnIdSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt32(result); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateAuthorReturnIdSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateAuthorReturnIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } private const string GetAuthorByIdSql = "SELECT id, name, bio FROM authors WHERE id = @id LIMIT 1 "; @@ -145,25 +247,54 @@ public class GetAuthorByIdArgs }; public async Task GetAuthorById(GetAuthorByIdArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorByIdSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@id", args.Id); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorByIdSql, connection)) { - if (await reader.ReadAsync()) + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) { - return new GetAuthorByIdRow + if (await reader.ReadAsync()) { - Id = reader.GetInt32(0), - Name = reader.GetString(1), - Bio = reader.IsDBNull(2) ? null : reader.GetString(2) - }; + return new GetAuthorByIdRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByIdSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@id", args.Id); + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetAuthorByIdRow + { + Id = reader.GetInt32(0), + Name = reader.GetString(1), + Bio = reader.IsDBNull(2) ? null : reader.GetString(2) + }; + } + } } return null; @@ -182,22 +313,47 @@ public class GetAuthorByNamePatternArgs }; public async Task> GetAuthorByNamePattern(GetAuthorByNamePatternArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorByNamePatternSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorByNamePatternSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorByNamePatternSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name_pattern", args.NamePattern ?? (object)DBNull.Value); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorByNamePatternRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -209,15 +365,31 @@ public class UpdateAuthorsArgs }; public async Task UpdateAuthors(UpdateAuthorsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(UpdateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); - return await command.ExecuteNonQueryAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(UpdateAuthorsSql, connection)) + { + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = UpdateAuthorsSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@bio", args.Bio ?? (object)DBNull.Value); + return await command.ExecuteNonQueryAsync(); + } } private const string GetAuthorsByIdsSql = "SELECT id, name, bio FROM authors WHERE id IN (/*SLICE:ids*/@ids)"; @@ -233,25 +405,51 @@ public class GetAuthorsByIdsArgs }; public async Task> GetAuthorsByIds(GetAuthorsByIdsArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - using (var command = new SqliteCommand(transformedSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -270,28 +468,56 @@ public class GetAuthorsByIdsAndNamesArgs }; public async Task> GetAuthorsByIdsAndNames(GetAuthorsByIdsAndNamesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + var transformedSql = GetAuthorsByIdsAndNamesSql; + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); + transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); + if (this.Transaction == null) { - await connection.OpenAsync(); - var transformedSql = GetAuthorsByIdsAndNamesSql; - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Ids.Length, "ids"); - transformedSql = Utils.TransformQueryForSliceArgs(transformedSql, args.Names.Length, "names"); - using (var command = new SqliteCommand(transformedSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - for (int i = 0; i < args.Ids.Length; i++) - command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); - for (int i = 0; i < args.Names.Length; i++) - command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(transformedSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = transformedSql; + command.Transaction = this.Transaction; + for (int i = 0; i < args.Ids.Length; i++) + command.Parameters.AddWithValue($"@idsArg{i}", args.Ids[i]); + for (int i = 0; i < args.Names.Length; i++) + command.Parameters.AddWithValue($"@namesArg{i}", args.Names[i]); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByIdsAndNamesRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }); } + + return result; } } } @@ -303,14 +529,32 @@ public class DeleteAuthorArgs }; public async Task DeleteAuthor(DeleteAuthorArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAuthorSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAuthorSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAuthorSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + await command.ExecuteNonQueryAsync(); } } @@ -326,17 +570,35 @@ public class CreateBookArgs }; public async Task CreateBook(CreateBookArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(CreateBookSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - command.Parameters.AddWithValue("@author_id", args.AuthorId); - var result = await command.ExecuteScalarAsync(); - return Convert.ToInt32(result); + await connection.OpenAsync(); + using (var command = new SqliteCommand(CreateBookSql, connection)) + { + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = CreateBookSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + command.Parameters.AddWithValue("@author_id", args.AuthorId); + var result = await command.ExecuteScalarAsync(); + return Convert.ToInt32(result); + } } private const string ListAllAuthorsBooksSql = "SELECT authors . id , authors . name, authors . bio, books . id, books . name, books . author_id, books . description FROM authors INNER JOIN books ON authors . id = books . author_id ORDER BY authors . name "; @@ -347,21 +609,45 @@ public class ListAllAuthorsBooksRow }; public async Task> ListAllAuthorsBooks() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(ListAllAuthorsBooksSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = ListAllAuthorsBooksSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new ListAllAuthorsBooksRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -374,21 +660,45 @@ public class GetDuplicateAuthorsRow }; public async Task> GetDuplicateAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetDuplicateAuthorsSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); + } + + return result; } + } + } + } - return result; + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetDuplicateAuthorsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetDuplicateAuthorsRow { Author = new Author { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2) }, Author2 = new Author { Id = reader.GetInt32(3), Name = reader.GetString(4), Bio = reader.IsDBNull(5) ? null : reader.GetString(5) } }); } + + return result; } } } @@ -407,22 +717,47 @@ public class GetAuthorsByBookNameArgs }; public async Task> GetAuthorsByBookName(GetAuthorsByBookNameArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@name", args.Name); - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetAuthorsByBookNameSql, connection)) { - var result = new List(); - while (await reader.ReadAsync()) + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) { - result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); + } + + return result; } + } + } + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } - return result; + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetAuthorsByBookNameSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@name", args.Name); + using (var reader = await command.ExecuteReaderAsync()) + { + var result = new List(); + while (await reader.ReadAsync()) + { + result.Add(new GetAuthorsByBookNameRow { Id = reader.GetInt32(0), Name = reader.GetString(1), Bio = reader.IsDBNull(2) ? null : reader.GetString(2), Book = new Book { Id = reader.GetInt32(3), Name = reader.GetString(4), AuthorId = reader.GetInt32(5), Description = reader.IsDBNull(6) ? null : reader.GetString(6) } }); } + + return result; } } } @@ -430,13 +765,30 @@ public async Task> GetAuthorsByBookName(GetAuthors private const string DeleteAllAuthorsSql = "DELETE FROM authors"; public async Task DeleteAllAuthors() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAllAuthorsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAllAuthorsSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllAuthorsSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } @@ -450,17 +802,38 @@ public class InsertSqliteTypesArgs }; public async Task InsertSqliteTypes(InsertSqliteTypesArgs args) { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(InsertSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); - command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(InsertSqliteTypesSql, connection)) + { + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = InsertSqliteTypesSql; + command.Transaction = this.Transaction; + command.Parameters.AddWithValue("@c_integer", args.CInteger ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_real", args.CReal ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_text", args.CText ?? (object)DBNull.Value); + command.Parameters.AddWithValue("@c_blob", args.CBlob ?? (object)DBNull.Value); + await command.ExecuteNonQueryAsync(); } } @@ -501,25 +874,54 @@ public class GetSqliteTypesRow }; public async Task GetSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteTypesSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteTypesRow + if (await reader.ReadAsync()) { - CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), - CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), - CText = reader.IsDBNull(2) ? null : reader.GetString(2), - CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) - }; + return new GetSqliteTypesRow + { + CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteTypesSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteTypesRow + { + CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3) + }; + } + } } return null; @@ -536,26 +938,56 @@ public class GetSqliteTypesCntRow }; public async Task GetSqliteTypesCnt() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteTypesCntSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteTypesCntSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteTypesCntRow + if (await reader.ReadAsync()) { - CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), - CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), - CText = reader.IsDBNull(2) ? null : reader.GetString(2), - CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), - Cnt = reader.GetInt32(4) - }; + return new GetSqliteTypesCntRow + { + CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + Cnt = reader.GetInt32(4) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteTypesCntSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteTypesCntRow + { + CInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + CReal = reader.IsDBNull(1) ? (decimal? )null : reader.GetDecimal(1), + CText = reader.IsDBNull(2) ? null : reader.GetString(2), + CBlob = reader.IsDBNull(3) ? null : reader.GetFieldValue(3), + Cnt = reader.GetInt32(4) + }; + } + } } return null; @@ -570,24 +1002,52 @@ public class GetSqliteFunctionsRow }; public async Task GetSqliteFunctions() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(GetSqliteFunctionsSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - using (var reader = await command.ExecuteReaderAsync()) + await connection.OpenAsync(); + using (var command = new SqliteCommand(GetSqliteFunctionsSql, connection)) { - if (await reader.ReadAsync()) + using (var reader = await command.ExecuteReaderAsync()) { - return new GetSqliteFunctionsRow + if (await reader.ReadAsync()) { - MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), - MaxReal = reader.GetDecimal(1), - MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) - }; + return new GetSqliteFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxReal = reader.GetDecimal(1), + MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) + }; + } } } } + + return null; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = GetSqliteFunctionsSql; + command.Transaction = this.Transaction; + using (var reader = await command.ExecuteReaderAsync()) + { + if (await reader.ReadAsync()) + { + return new GetSqliteFunctionsRow + { + MaxInteger = reader.IsDBNull(0) ? (int? )null : reader.GetInt32(0), + MaxReal = reader.GetDecimal(1), + MaxText = reader.IsDBNull(2) ? null : reader.GetValue(2) + }; + } + } } return null; @@ -596,13 +1056,30 @@ public async Task GetSqliteFunctions() private const string DeleteAllSqliteTypesSql = "DELETE FROM types_sqlite"; public async Task DeleteAllSqliteTypes() { - using (var connection = new SqliteConnection(ConnectionString)) + if (this.Transaction == null) { - await connection.OpenAsync(); - using (var command = new SqliteCommand(DeleteAllSqliteTypesSql, connection)) + using (var connection = new SqliteConnection(ConnectionString)) { - await command.ExecuteScalarAsync(); + await connection.OpenAsync(); + using (var command = new SqliteCommand(DeleteAllSqliteTypesSql, connection)) + { + await command.ExecuteNonQueryAsync(); + } } + + return; + } + + if (this.Transaction?.Connection == null || this.Transaction?.Connection.State != System.Data.ConnectionState.Open) + { + throw new System.InvalidOperationException("Transaction is provided, but its connection is null."); + } + + using (var command = this.Transaction.Connection.CreateCommand()) + { + command.CommandText = DeleteAllSqliteTypesSql; + command.Transaction = this.Transaction; + await command.ExecuteNonQueryAsync(); } } }