diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 000000000..857a5990a
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,22 @@
+# Top-most EditorConfig file
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+tab_width = 4
+trim_trailing_whitespace = true
+insert_final_newline = true
+end_of_line = lf
+
+[*.{csproj,props,build}]
+indent_size = 2
+
+[*.{cs,vb}]
+# Organize usings
+dotnet_separate_import_directive_groups = false
+dotnet_sort_system_directives_first = true
+
+[*.cs]
+# CS1574: XML comment has cref attribute that could not be resolved
+dotnet_diagnostic.CS1574.severity = none
diff --git a/.github/workflows/build-pr.yml b/.github/workflows/build-pr.yml
new file mode 100644
index 000000000..929a55029
--- /dev/null
+++ b/.github/workflows/build-pr.yml
@@ -0,0 +1,69 @@
+name: Build & Run Tests for PR
+on:
+ pull_request:
+
+env:
+ REPODB_SQLSERVER_CONSTR_MASTER: "Server=tcp:127.0.0.1,41433;Database=master;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_SQLSERVER_CONSTR_REPODB: "Server=tcp:127.0.0.1,41433;Database=RepoDb;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_SQLSERVER_CONSTR_REPODBTEST: "Server=tcp:127.0.0.1,41433;Database=RepoDbTest;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_POSTGRESQL_CONSTR_POSTGRESDB: "Server=127.0.0.1;Port=45432;Database=postgres;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_POSTGRESQL_CONSTR: "Server=127.0.0.1;Port=45432;Database=RepoDb;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_POSTGRESQL_CONSTR_BULK: "Server=127.0.0.1;Port=45432;Database=RepoDbBulk;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_SYS: "Server=127.0.0.1;Port=43306;Database=sys;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_REPODB: "Server=127.0.0.1;Port=43306;Database=RepoDb;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_REPODBTEST: "Server=127.0.0.1;Port=43306;Database=RepoDbTest;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ # Services. See docker-compose.yml
+ services:
+ mssql:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ ports:
+ - 127.0.0.1:41433:1433
+ env:
+ ACCEPT_EULA: true
+ MSSQL_SA_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ postgresql:
+ image: postgres:latest
+ ports:
+ - 127.0.0.1:45432:5432
+ env:
+ POSTGRES_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ mysql:
+ image: mysql:latest
+ ports:
+ - 127.0.0.1:43306:3306
+ env:
+ MYSQL_ROOT_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ steps:
+ - name: Check out repository code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET Versions
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: |
+ 6.0.x
+ 7.0.x
+ 8.0.x
+
+ - name: build
+ run: dotnet build -c release
+
+ - name: test
+ run: dotnet test -c release -f net8.0 --no-build -p:TestingPlatformShowTestsFailure=true -p:TestingPlatformCaptureOutput=false
+
+ - name: pack packages
+ run: dotnet pack -c release -p Version="1.14.0-dev-pr-${{ github.run_number }}" -o release RepoDb.Core/RepoDb.All.sln
+
+ - name: Package nupkg files
+ uses: actions/upload-artifact@v3
+ with:
+ name: release
+ path: release/*nupkg
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 000000000..cef059433
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,69 @@
+name: Build & Run Tests (Push)
+on:
+ push
+
+env:
+ REPODB_SQLSERVER_CONSTR_MASTER: "Server=tcp:127.0.0.1,41433;Database=master;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_SQLSERVER_CONSTR_REPODB: "Server=tcp:127.0.0.1,41433;Database=RepoDb;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_SQLSERVER_CONSTR_REPODBTEST: "Server=tcp:127.0.0.1,41433;Database=RepoDbTest;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;"
+ REPODB_POSTGRESQL_CONSTR_POSTGRESDB: "Server=127.0.0.1;Port=45432;Database=postgres;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_POSTGRESQL_CONSTR: "Server=127.0.0.1;Port=45432;Database=RepoDb;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_POSTGRESQL_CONSTR_BULK: "Server=127.0.0.1;Port=45432;Database=RepoDbBulk;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_SYS: "Server=127.0.0.1;Port=43306;Database=sys;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_REPODB: "Server=127.0.0.1;Port=43306;Database=RepoDb;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+ REPODB_MYSQL_CONSTR_REPODBTEST: "Server=127.0.0.1;Port=43306;Database=RepoDbTest;User ID=root;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;"
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ # Services. See docker-compose.yml
+ services:
+ mssql:
+ image: mcr.microsoft.com/mssql/server:2022-latest
+ ports:
+ - 127.0.0.1:41433:1433
+ env:
+ ACCEPT_EULA: true
+ MSSQL_SA_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ postgresql:
+ image: postgres:latest
+ ports:
+ - 127.0.0.1:45432:5432
+ env:
+ POSTGRES_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ mysql:
+ image: mysql:latest
+ ports:
+ - 127.0.0.1:43306:3306
+ env:
+ MYSQL_ROOT_PASSWORD: ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2
+
+ steps:
+ - name: Check out repository code
+ uses: actions/checkout@v4
+
+ - name: Setup .NET Versions
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: |
+ 6.0.x
+ 7.0.x
+ 8.0.x
+
+ - name: build
+ run: dotnet build -c release RepoDb.Core/RepoDb.All.sln
+
+ - name: test for .Net 8.0
+ run: dotnet test -c release -f net8.0 --no-build -p:TestingPlatformShowTestsFailure=true -p:TestingPlatformCaptureOutput=false RepoDb.Core/RepoDb.All.sln
+
+ - name: pack packages
+ run: dotnet pack -c release -p Version="1.14.0-dev-${{ github.run_number }}" -o release RepoDb.Core/RepoDb.All.sln
+
+ - name: Package nupkg files
+ uses: actions/upload-artifact@v3
+ with:
+ name: release
+ path: release/*nupkg
diff --git a/Directory.Build.props b/Directory.Build.props
index fc92cd4ad..d115e6210 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,13 +1,28 @@
- Michael Camara Pendon
+ Michael Camara Pendon and others
RepoDb
RepoDb
+ 0.0.1-dev
default
- Copyright © 2020
+ Copyright © 2020-2024
https://repodb.net/
Github
LICENSE.txt
+ README.md
+ true
+ true
+ portable
+ true
+ annotations
+ true
+ true
-
\ No newline at end of file
+
+
+
+ true
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 000000000..0b5b6f38d
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,43 @@
+
+
+ true
+ true
+ $(NoWarn);NU1507
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/RepoDb.Benchmarks/RepoDb.Benchmarks.PostgreSql/RepoDb.Benchmarks.PostgreSql.csproj b/RepoDb.Benchmarks/RepoDb.Benchmarks.PostgreSql/RepoDb.Benchmarks.PostgreSql.csproj
index 497feb51c..3f7703a5d 100644
--- a/RepoDb.Benchmarks/RepoDb.Benchmarks.PostgreSql/RepoDb.Benchmarks.PostgreSql.csproj
+++ b/RepoDb.Benchmarks/RepoDb.Benchmarks.PostgreSql/RepoDb.Benchmarks.PostgreSql.csproj
@@ -1,24 +1,21 @@
-
Exe
net6.0;net7.0;net8.0
+ false
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
+
\ No newline at end of file
diff --git a/RepoDb.Benchmarks/RepoDb.Benchmarks.SqlServer/RepoDb.Benchmarks.SqlServer.csproj b/RepoDb.Benchmarks/RepoDb.Benchmarks.SqlServer/RepoDb.Benchmarks.SqlServer.csproj
index 357b438bb..935276dba 100644
--- a/RepoDb.Benchmarks/RepoDb.Benchmarks.SqlServer/RepoDb.Benchmarks.SqlServer.csproj
+++ b/RepoDb.Benchmarks/RepoDb.Benchmarks.SqlServer/RepoDb.Benchmarks.SqlServer.csproj
@@ -1,24 +1,21 @@
-
Exe
net6.0;net7.0;net8.0
+ false
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
\ No newline at end of file
diff --git a/RepoDb.Core/.editorconfig b/RepoDb.Core/.editorconfig
deleted file mode 100644
index 16cd8ca45..000000000
--- a/RepoDb.Core/.editorconfig
+++ /dev/null
@@ -1,4 +0,0 @@
-[*.cs]
-
-# CS1574: XML comment has cref attribute that could not be resolved
-dotnet_diagnostic.CS1574.severity = none
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/BaseEnferredInheritanceTest.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/BaseEnferredInheritanceTest.cs
index 1eca2b7b3..19c7e2e2e 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/BaseEnferredInheritanceTest.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/BaseEnferredInheritanceTest.cs
@@ -1,6 +1,6 @@
using System;
-using Microsoft.Data.SqlClient;
using System.Linq;
+using Microsoft.Data.SqlClient;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RepoDb.IntegrationTests.Models;
using RepoDb.IntegrationTests.Setup;
@@ -100,6 +100,7 @@ public void TestSqlConnectionInsertForInherited()
public void TestSqlConnectionInsertAllForInherited()
{
// Setup
+ // warning CA2021: This call will always result in an empty sequence because type 'RepoDb.IntegrationTests.Models.InheritedIdentityTable' is incompatible with type 'RepoDb.IntegrationTests.Models.Entity' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)
var entities = Helper.CreateInheritedIdentityTables(10)
.OfType>().ToList();
@@ -192,6 +193,7 @@ public void TestSqlConnectionMergeForInheritedWithNonEmptyTable()
public void TestSqlConnectionMergeAllForInherited()
{
// Setup
+ // warning CA2021: This call will always result in an empty sequence because type 'RepoDb.IntegrationTests.Models.InheritedIdentityTable' is incompatible with type 'RepoDb.IntegrationTests.Models.Entity' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)
var entities = Helper.CreateInheritedIdentityTables(10)
.OfType>().ToList();
@@ -217,6 +219,7 @@ public void TestSqlConnectionMergeAllForInherited()
public void TestSqlConnectionMergeAllForInheritedWithNonEmptyTables()
{
// Setup
+ // warning CA2021: This call will always result in an empty sequence because type 'RepoDb.IntegrationTests.Models.InheritedIdentityTable' is incompatible with type 'RepoDb.IntegrationTests.Models.Entity' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)
var entities = Helper.CreateInheritedIdentityTables(10)
.OfType>().ToList();
@@ -344,6 +347,7 @@ public void TestSqlConnectionUpdateForInheritedViaPrimaryKey()
public void TestSqlConnectionUpdateAllForInherited()
{
// Setup
+ // warning CA2021: This call will always result in an empty sequence because type 'RepoDb.IntegrationTests.Models.InheritedIdentityTable' is incompatible with type 'RepoDb.IntegrationTests.Models.Entity' (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2021)
var entities = Helper.CreateInheritedIdentityTables(10)
.OfType>().ToList();
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/CultureScope.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/CultureScope.cs
index 1233373c2..bd733eeaf 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/CultureScope.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/CultureScope.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Generic;
using System.Globalization;
-using System.Text;
namespace RepoDb.IntegrationTests
{
@@ -11,16 +9,20 @@ namespace RepoDb.IntegrationTests
///
internal sealed class CultureScope : IDisposable
{
- private readonly CultureInfo original;
+ private readonly CultureInfo originalCulture;
+ private readonly CultureInfo originalUICulture;
+
public CultureScope(string cultureName)
{
- original = CultureInfo.DefaultThreadCurrentCulture;
- CultureInfo.DefaultThreadCurrentCulture = CultureInfo.GetCultureInfo(cultureName);
+ originalCulture = CultureInfo.CurrentCulture;
+ originalUICulture = CultureInfo.CurrentUICulture;
+ CultureInfo.CurrentUICulture = CultureInfo.CurrentCulture = CultureInfo.GetCultureInfo(cultureName);
}
public void Dispose()
{
- CultureInfo.DefaultThreadCurrentCulture = original;
+ CultureInfo.CurrentUICulture = originalUICulture;
+ CultureInfo.CurrentCulture = originalCulture;
}
}
}
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/RepoDb.IntegrationTests.csproj b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/RepoDb.IntegrationTests.csproj
index 4792bb95b..905740377 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/RepoDb.IntegrationTests.csproj
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/RepoDb.IntegrationTests.csproj
@@ -1,10 +1,11 @@
-
net6.0;net7.0;net8.0
false
+ true
+ true
+ true
-
@@ -25,24 +26,18 @@
-
-
-
-
-
-
+
+
-
-
-
+
\ No newline at end of file
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/Setup/Database.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/Setup/Database.cs
index 2805933c3..52fcc92fd 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/Setup/Database.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/Setup/Database.cs
@@ -13,15 +13,19 @@ public static class Database
///
public static void Initialize()
{
- // Get the connection string
- var connectionStringForMaster = Environment.GetEnvironmentVariable("REPODB_CONSTR_MASTER", EnvironmentVariableTarget.Process);
- var connectionString = Environment.GetEnvironmentVariable("REPODB_CONSTR", EnvironmentVariableTarget.Process);
-
// Master connection
- ConnectionStringForMaster = (connectionStringForMaster ?? @"Server=(local);Database=master;Integrated Security=SSPI;TrustServerCertificate=True;");
+ ConnectionStringForMaster =
+ Environment.GetEnvironmentVariable("REPODB_SQLSERVER_CONSTR_MASTER")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR_MASTER")
+ // ?? "Server=tcp:127.0.0.1,41433;Database=master;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;" // Docker test configuration
+ ?? "Server=(local);Database=master;Integrated Security=SSPI;TrustServerCertificate=True;";
// RepoDb connection
- ConnectionStringForRepoDb = (connectionString ?? @"Server=(local);Database=RepoDb;Integrated Security=SSPI;TrustServerCertificate=True;");
+ ConnectionStringForRepoDb =
+ Environment.GetEnvironmentVariable("REPODB_SQLSERVER_CONSTR_REPODB")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR")
+ // ?? "Server=tcp:127.0.0.1,41433;Database=RepoDb;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;" // Docker test configuration
+ ?? "Server=(local);Database=RepoDb;Integrated Security=SSPI;TrustServerCertificate=True;";
// Set the proper values for type mapper
TypeMapper.Add(typeof(DateTime), System.Data.DbType.DateTime2, true);
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/TypeConversionsTest.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/TypeConversionsTest.cs
index ba80999e6..2c5c91cd6 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/TypeConversionsTest.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.IntegrationTests/TypeConversionsTest.cs
@@ -1,10 +1,11 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System;
+using System.ComponentModel;
+using System.Linq;
+using Microsoft.Data.SqlClient;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using RepoDb.Attributes;
using RepoDb.Enumerations;
using RepoDb.IntegrationTests.Setup;
-using System;
-using Microsoft.Data.SqlClient;
-using System.Linq;
namespace RepoDb.IntegrationTests
{
@@ -134,6 +135,7 @@ public void TestSqlConnectionExecuteQueryConversionFromStringToBit()
[TestMethod]
public void TestSqlConnectionExecuteQueryConversionFromStringToDecimal()
{
+ using var _ = new CultureScope("EN-US");
using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
{
// Act Query
@@ -147,6 +149,7 @@ public void TestSqlConnectionExecuteQueryConversionFromStringToDecimal()
[TestMethod]
public void TestSqlConnectionExecuteQueryConversionFromStringToFloat()
{
+ using var _ = new CultureScope("EN-US");
using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
{
// Act Query
@@ -263,6 +266,7 @@ public void TestSqlConnectionExecuteQueryConversionFromDecimalToDecimal()
[TestMethod]
public void TestSqlConnectionExecuteQueryConversionFromDecimalToString()
{
+ using var _ = new CultureScope("EN-US");
using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
{
// Act Query
@@ -306,6 +310,7 @@ public void TestSqlConnectionExecuteQueryConversionFromRealToFloat()
[TestMethod]
public void TestSqlConnectionExecuteQueryConversionFromRealToString()
{
+ using var _ = new CultureScope("EN-US");
using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
{
// Act Query
@@ -424,6 +429,298 @@ public void TestSqlConnectionExecuteQueryConversionFromBitToString()
#endregion
+
+ enum Direction
+ {
+ None,
+ North,
+ East,
+ South,
+ West
+ }
+ enum Direction2
+ {
+ None,
+ North,
+ East,
+ South,
+ West
+ }
+
+ enum Direction3
+ {
+ None,
+ North,
+ East,
+ South,
+ West
+ }
+
+ enum Direction4
+ {
+ None,
+ North,
+ East,
+ South,
+ West
+ }
+
+ [TestMethod]
+ public void TestSqlConnectionExecuteQueryConversionFromIntToEnum()
+ {
+ using var _ = new CultureScope("EN-US");
+
+ // With automatic conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT CONVERT(INT, 1) AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT CONVERT(INT, 0) AS Value;").First();
+ var data10 = connection.ExecuteQuery("SELECT CONVERT(INT, 10) AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction.North, data);
+ Assert.AreEqual(Direction.None, data0);
+ Assert.AreEqual((Direction)10, data10);
+ }
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.UseDefault });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT CONVERT(INT, 1) AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT CONVERT(INT, 0) AS Value;").First();
+ var data10 = connection.ExecuteQuery("SELECT CONVERT(INT, 10) AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction2.North, data);
+ Assert.AreEqual(Direction2.None, data0);
+ Assert.AreEqual(Direction2.None, data10);
+ }
+
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.ThrowError });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT CONVERT(INT, 1) AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT CONVERT(INT, 0) AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction3.North, data);
+ Assert.AreEqual(Direction3.None, data0);
+
+ try
+ {
+ var data10 = connection.ExecuteQuery("SELECT CONVERT(INT, 10) AS Value;").First();
+ Assert.Fail("Should have failed");
+ }
+ catch (InvalidEnumArgumentException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction3)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("The value of argument 'value' (10) is invalid for Enum type 'Direction3'. (Parameter 'value')", e.Message);
+ }
+ }
+ }
+
+ [TestMethod]
+ public void TestSqlConnectionExecuteQueryConversionFromStringToEnum()
+ {
+ using var _ = new CultureScope("EN-US");
+
+ // With automatic conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North' AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT 'None' AS Value;").First();
+ var data3 = connection.ExecuteQuery("SELECT '3' AS Value;").First();
+ var data9 = connection.ExecuteQuery("SELECT '9' AS Value;").First();
+ try
+ {
+ var data10 = connection.ExecuteQuery("SELECT 'Center' AS Value;").First();
+ Assert.Fail("Should have failed Direction/3");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction (Parameter 'value')\nActual value was Center.", e.Message.Replace("\r", ""));
+ }
+
+ // Assert
+ Assert.AreEqual(Direction.North, data);
+ Assert.AreEqual(Direction.South, data3);
+ Assert.AreEqual(Direction.None, data0);
+ Assert.AreEqual((Direction)9, data9);
+ }
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.UseDefault });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North' AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT 'None' AS Value;").First();
+ var data3 = connection.ExecuteQuery("SELECT '3' AS Value;").First();
+ var data9 = connection.ExecuteQuery("SELECT '9' AS Value;").First();
+ var data10 = connection.ExecuteQuery("SELECT 'Center' AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction2.North, data);
+ Assert.AreEqual(Direction2.None, data0);
+ Assert.AreEqual(Direction2.South, data3);
+ Assert.AreEqual(Direction2.None, data9);
+ Assert.AreEqual(Direction2.None, data10);
+ }
+
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.ThrowError });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North' AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT 'None' AS Value;").First();
+
+ try
+ {
+ var data10 = connection.ExecuteQuery("SELECT 'Center' AS Value;").First();
+ Assert.Fail("Should have failed Direction3/Center");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction3)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction3 (Parameter 'value')\nActual value was Center.", e.Message.Replace("\r", ""));
+ }
+
+ try
+ {
+ var data9 = connection.ExecuteQuery("SELECT '9' AS Value;").First();
+ Assert.Fail("Should have failed Direction3/9");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction3)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction3 (Parameter 'value')\nActual value was 9.", e.Message.Replace("\r", ""));
+ }
+
+ // Assert
+ Assert.AreEqual(Direction3.North, data);
+ Assert.AreEqual(Direction3.None, data0);
+ }
+
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.ThrowError });
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North' AS Value;").First();
+ var data0 = connection.ExecuteQuery("SELECT 'None' AS Value;").First();
+ var data3 = connection.ExecuteQuery("SELECT '3' AS Value;").First();
+ try
+ {
+ var data10 = connection.ExecuteQuery("SELECT 'Center' AS Value;").First();
+ Assert.Fail("Should have failed Direction/3");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction4)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction4 (Parameter 'value')\nActual value was Center.", e.Message.Replace("\r", ""));
+ }
+
+ try
+ {
+ var data9 = connection.ExecuteQuery("SELECT '9' AS Value;").First();
+ Assert.Fail("Should have failed Direction/9");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction4)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction4 (Parameter 'value')\nActual value was 9.", e.Message.Replace("\r", ""));
+ }
+
+ // Assert
+ Assert.AreEqual(Direction4.North, data);
+ Assert.AreEqual(Direction4.South, data3);
+ Assert.AreEqual(Direction4.None, data0);
+ }
+ }
+
+ [TestMethod]
+ public void TestSqlConnectionExecuteQueryConversionFromStringToEnumFlags()
+ {
+ using var _ = new CultureScope("EN-US");
+
+ // With automatic conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North, East' AS Value;").First();
+ var data2 = connection.ExecuteQuery("SELECT 'North, West' AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction.South, data); // Flag behavior
+ Assert.AreEqual(Direction.North | Direction.West, data2); // Flag behavior
+ }
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.UseDefault });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North, East' AS Value;").First();
+ var data2 = connection.ExecuteQuery("SELECT 'North, West' AS Value;").First();
+
+ // Assert
+ Assert.AreEqual(Direction2.South, data); // Flag behavior
+ Assert.AreEqual(Direction2.None, data2); // Not defined
+ }
+
+
+ GlobalConfiguration.Setup(new() { ConversionType = ConversionType.Default, EnumHandling = EnumHandling.ThrowError });
+
+ // With default conversion
+ using (var connection = new SqlConnection(Database.ConnectionStringForRepoDb).EnsureOpen())
+ {
+ // Act Query
+ var data = connection.ExecuteQuery("SELECT 'North, East' AS Value;").First();
+
+ try
+ {
+ var data2 = connection.ExecuteQuery("SELECT 'North, West' AS Value;").First();
+ Assert.Fail("Should have failed Direction3/North, West");
+ }
+ catch (ArgumentOutOfRangeException e)
+ {
+ Assert.IsTrue(e.Message.Contains(nameof(Direction3)));
+
+ // We are in an EN-US scope so the message should match
+ Assert.AreEqual("Invalid value for Direction3 (Parameter 'value')\nActual value was North, West.", e.Message.Replace("\r", ""));
+ }
+
+ Assert.AreEqual(Direction3.South, data);
+ }
+ }
+
#endregion
#region Query
@@ -521,6 +818,7 @@ private class StringToDecimalClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToDecimal()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToDecimalClass
{
@@ -556,6 +854,7 @@ private class StringToFloatClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToFloat()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToFloatClass
{
@@ -626,6 +925,7 @@ private class StringToMoneyClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToMoney()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToMoneyClass
{
@@ -661,6 +961,7 @@ private class StringToNumericClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToNumeric()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToNumericClass
{
@@ -696,6 +997,7 @@ private class StringToRealClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToReal()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToRealClass
{
@@ -766,6 +1068,7 @@ private class StringToSmallMoneyClass
[TestMethod]
public void TestSqlConnectionInsertAndQueryConversionFromStringToSmallMoney()
{
+ using var _ = new CultureScope("EN-US");
// Setup
var entity = new StringToSmallMoneyClass
{
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Equalities/QueryGroupEqualityTest.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Equalities/QueryGroupEqualityTest.cs
index 14d8f34ec..8409ca570 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Equalities/QueryGroupEqualityTest.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Equalities/QueryGroupEqualityTest.cs
@@ -1,8 +1,8 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Collections;
+using System.Collections.Generic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
using RepoDb.Enumerations;
using RepoDb.Extensions;
-using System.Collections;
-using System.Collections.Generic;
namespace RepoDb.UnitTests.Equalities
{
@@ -128,6 +128,22 @@ public void TestQueryGroupHashCodeEqualityForCollidedExpressions()
// Assert
Assert.IsFalse(equal);
+ Assert.AreEqual(objA.QueryGroups.Count, objB.QueryGroups.Count);
+ }
+
+ [TestMethod]
+ public void TestQueryGroupHashCodeEqualityForCollidedExpressions2()
+ {
+ // Prepare
+ var objA = QueryGroup.Parse(c => c.Id == 1 && !(c.Value != 1));
+ var objB = QueryGroup.Parse(c => c.Id != 1 && c.Value == 1);
+
+ // Act
+ var equal = (objA.GetHashCode() == objB.GetHashCode());
+
+ // Assert
+ Assert.IsFalse(equal);
+ Assert.AreEqual(objA.QueryGroups?.Count, objB.QueryGroups?.Count);
}
[TestMethod]
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Mappers/MappingSequenceTest.cs b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Mappers/MappingSequenceTest.cs
index b88ea4a78..746b7d2ed 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Mappers/MappingSequenceTest.cs
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/Mappers/MappingSequenceTest.cs
@@ -1,13 +1,10 @@
-using Microsoft.VisualStudio.TestTools.UnitTesting;
-using RepoDb.Interfaces;
-using RepoDb.Attributes;
-using RepoDb.UnitTests.CustomObjects;
-using System;
-using System.Linq;
-using System.Collections.Generic;
+using System;
using System.Data;
-using System.Text;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using RepoDb.Attributes;
+using RepoDb.Interfaces;
using RepoDb.Options;
+using RepoDb.UnitTests.CustomObjects;
namespace RepoDb.UnitTests.Mappers
{
diff --git a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/RepoDb.UnitTests.csproj b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/RepoDb.UnitTests.csproj
index d3f47bf71..1013c1d15 100644
--- a/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/RepoDb.UnitTests.csproj
+++ b/RepoDb.Core/RepoDb.Tests/RepoDb.UnitTests/RepoDb.UnitTests.csproj
@@ -1,10 +1,11 @@
-
net6.0;net7.0;net8.0
false
+ true
+ true
+ true
-
@@ -15,17 +16,13 @@
-
-
-
-
-
-
+
+
+
-
-
+
\ No newline at end of file
diff --git a/RepoDb.Core/RepoDb/Compat.cs b/RepoDb.Core/RepoDb/Compat.cs
new file mode 100644
index 000000000..0cab4c37f
--- /dev/null
+++ b/RepoDb.Core/RepoDb/Compat.cs
@@ -0,0 +1,9 @@
+namespace System.Runtime.CompilerServices
+{
+#if !NET
+ // Required to allow init properties in netstandard
+ internal sealed class IsExternalInit : Attribute
+ {
+ }
+#endif
+}
diff --git a/RepoDb.Core/RepoDb/DbField.cs b/RepoDb.Core/RepoDb/DbField.cs
index 0d2b8386d..d8dda9d7e 100644
--- a/RepoDb.Core/RepoDb/DbField.cs
+++ b/RepoDb.Core/RepoDb/DbField.cs
@@ -119,6 +119,13 @@ public DbField(string name,
///
public string Provider { get; }
+
+ ///
+ /// Gets the type to map to, including nullable
+ ///
+ ///
+ public Type TypeNullable() => IsNullable && Type.IsValueType ? typeof(System.Nullable<>).MakeGenericType(Type) : Type;
+
#endregion
#region Methods
diff --git a/RepoDb.Core/RepoDb/Enumerations/EnumHandling.cs b/RepoDb.Core/RepoDb/Enumerations/EnumHandling.cs
new file mode 100644
index 000000000..3f4a49b45
--- /dev/null
+++ b/RepoDb.Core/RepoDb/Enumerations/EnumHandling.cs
@@ -0,0 +1,21 @@
+namespace RepoDb.Enumerations
+{
+ ///
+ ///
+ ///
+ public enum EnumHandling
+ {
+ ///
+ /// Throw an error when encountering non defined enum values. For enums decorated with a no value check is performed.
+ ///
+ ThrowError = 0,
+ ///
+ /// Use the default (0) value of the enum when encountering non defined enum values, For enums decorated with a no value check is performed.
+ ///
+ UseDefault = 1,
+ ///
+ /// Assumes all matched strings and integer values are valid.
+ ///
+ Cast = 2
+ }
+}
diff --git a/RepoDb.Core/RepoDb/Mappers/DbSettingMapper.cs b/RepoDb.Core/RepoDb/Mappers/DbSettingMapper.cs
index 88e9a88c1..cdab33a77 100644
--- a/RepoDb.Core/RepoDb/Mappers/DbSettingMapper.cs
+++ b/RepoDb.Core/RepoDb/Mappers/DbSettingMapper.cs
@@ -1,8 +1,8 @@
-using RepoDb.Exceptions;
-using RepoDb.Interfaces;
-using System;
+using System;
using System.Collections.Concurrent;
using System.Data;
+using RepoDb.Exceptions;
+using RepoDb.Interfaces;
namespace RepoDb
{
@@ -77,7 +77,7 @@ public static IDbSetting Get()
///
/// The type of .
/// The instance of .
- /// The instance of exising mapped object.
+ /// The instance of existing mapped object.
public static IDbSetting Get(TDbConnection connection)
where TDbConnection : IDbConnection
{
diff --git a/RepoDb.Core/RepoDb/Options/GlobalConfigurationOptions.cs b/RepoDb.Core/RepoDb/Options/GlobalConfigurationOptions.cs
index faef5fac3..8214e9cdb 100644
--- a/RepoDb.Core/RepoDb/Options/GlobalConfigurationOptions.cs
+++ b/RepoDb.Core/RepoDb/Options/GlobalConfigurationOptions.cs
@@ -1,37 +1,42 @@
-using RepoDb.Enumerations;
-using System.Data;
+using System.Data;
using System.Data.Common;
+using RepoDb.Enumerations;
namespace RepoDb.Options
{
///
/// A class that is being used to define the globalized configurations for the application.
///
- public class GlobalConfigurationOptions
+ public record GlobalConfigurationOptions
{
///
/// Gets or sets the value that defines the conversion logic when converting an instance of into a .NET CLR class.
///
- public ConversionType ConversionType { get; set; } = ConversionType.Default;
+ public ConversionType ConversionType { get; init; } = ConversionType.Default;
+
+ ///
+ /// Gets or sets the handling of invalid enum values when converting an instance of into .NET enum values
+ ///
+ public EnumHandling EnumHandling { get; init; } = EnumHandling.ThrowError;
///
/// Gets or sets the default value of the batch operation size. The value defines on this property mainly affects the batch size of the InsertAll, MergeAll and UpdateAll operations.
///
- public int DefaultBatchOperationSize { get; set; } = Constant.DefaultBatchOperationSize;
+ public int DefaultBatchOperationSize { get; init; } = Constant.DefaultBatchOperationSize;
///
/// Gets of sets the default value of the cache expiration in minutes.
///
- public int DefaultCacheItemExpirationInMinutes { get; set; } = Constant.DefaultCacheItemExpirationInMinutes;
+ public int DefaultCacheItemExpirationInMinutes { get; init; } = Constant.DefaultCacheItemExpirationInMinutes;
///
/// Gets or sets the default equivalent of an enumeration if it is being used as a parameter to the execution of any non-entity-based operations.
///
- public DbType EnumDefaultDatabaseType { get; set; } = DbType.String;
+ public DbType EnumDefaultDatabaseType { get; init; } = DbType.String;
///
/// Gets or sets the default value of how the push operations (i.e.: Insert, InsertAll, Merge and MergeAll) behaves when returning the value from the key columns (i.e.: Primary and Identity).
///
- public KeyColumnReturnBehavior KeyColumnReturnBehavior { get; set; } = KeyColumnReturnBehavior.IdentityOrElsePrimary;
+ public KeyColumnReturnBehavior KeyColumnReturnBehavior { get; init; } = KeyColumnReturnBehavior.IdentityOrElsePrimary;
}
}
diff --git a/RepoDb.Core/RepoDb/QueryGroup/ParseExpression.cs b/RepoDb.Core/RepoDb/QueryGroup/ParseExpression.cs
index 26b13d28c..1e5f88bc7 100644
--- a/RepoDb.Core/RepoDb/QueryGroup/ParseExpression.cs
+++ b/RepoDb.Core/RepoDb/QueryGroup/ParseExpression.cs
@@ -1,8 +1,8 @@
-using RepoDb.Enumerations;
-using RepoDb.Extensions;
-using System;
+using System;
using System.Linq;
using System.Linq.Expressions;
+using RepoDb.Enumerations;
+using RepoDb.Extensions;
namespace RepoDb
{
@@ -145,12 +145,29 @@ private static QueryGroup Parse(BinaryExpression expression)
private static QueryGroup Parse(UnaryExpression expression)
where TEntity : class
{
- return expression.Operand switch
+ if (expression.NodeType == ExpressionType.Not || expression.NodeType == ExpressionType.Convert)
{
- MemberExpression memberExpression => Parse(memberExpression, expression.NodeType),
- MethodCallExpression methodCallExpression => Parse(methodCallExpression, expression.NodeType),
- _ => null
- };
+ // These two handle
+ if (expression.Operand is MemberExpression memberExpression && Parse(memberExpression, expression.NodeType) is { } r1)
+ return r1;
+ else if (expression.Operand is MethodCallExpression methodCallExpression && Parse(methodCallExpression, expression.NodeType) is { } r2)
+ return r2;
+ }
+
+ if (Parse(expression.Operand) is { } r)
+ {
+ if (expression.NodeType == ExpressionType.Not)
+ {
+ // Wrap result in A NOT expression
+ return new QueryGroup(r, true);
+ }
+ else
+ return new QueryGroup(r, false);
+ }
+ else
+ {
+ throw new NotSupportedException($"Unary operation '{expression.NodeType}' is currently not supported.");
+ }
}
/*
diff --git a/RepoDb.Core/RepoDb/Reflection/Compiler/Options.cs b/RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.Options.cs
similarity index 100%
rename from RepoDb.Core/RepoDb/Reflection/Compiler/Options.cs
rename to RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.Options.cs
diff --git a/RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.cs b/RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.cs
index d62f2a4ab..9731a7e84 100644
--- a/RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.cs
+++ b/RepoDb.Core/RepoDb/Reflection/Compiler/Compiler.cs
@@ -1,15 +1,16 @@
-using RepoDb.Enumerations;
-using RepoDb.Exceptions;
-using RepoDb.Extensions;
-using RepoDb.Interfaces;
-using RepoDb.Resolvers;
using System;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
+using RepoDb.Enumerations;
+using RepoDb.Exceptions;
+using RepoDb.Extensions;
+using RepoDb.Interfaces;
+using RepoDb.Resolvers;
namespace RepoDb.Reflection
{
@@ -519,13 +520,6 @@ internal static MethodInfo GetDateTimeFromDateOnlyMethod() =>
StaticType.DateOnly.GetMethod("ToDateTime", new Type[] { StaticType.TimeOnly });
#endif
- ///
- ///
- ///
- ///
- internal static MethodInfo GetEnumParseMethod() =>
- StaticType.Enum.GetMethod("Parse", new[] { StaticType.Type, StaticType.String, StaticType.Boolean });
-
///
///
///
@@ -540,18 +534,40 @@ internal static MethodInfo GetEnumGetNameMethod() =>
internal static MethodInfo GetEnumIsDefinedMethod() =>
StaticType.Enum.GetMethod("IsDefined", new[] { StaticType.Type, StaticType.Object });
+
+ internal static MethodInfo GetEnumParseNullMethod() =>
+ typeof(Compiler).GetMethod(nameof(EnumParseNull), BindingFlags.Static | BindingFlags.NonPublic);
+
+ private static TEnum? EnumParseNull(string value) where TEnum : struct, System.Enum
+ {
+ if (Enum.TryParse(value, true, out var r))
+ return r;
+ else
+ return null;
+ }
+
+ internal static MethodInfo GetEnumParseNullDefinedMethod() =>
+ typeof(Compiler).GetMethod(nameof(EnumParseNullDefined), BindingFlags.Static | BindingFlags.NonPublic);
+
+ private static TEnum? EnumParseNullDefined(string value) where TEnum : struct, System.Enum
+ {
+ if (Enum.TryParse(value, true, out var r) && Enum.IsDefined(typeof(TEnum), r))
+ return r;
+ else
+ return null;
+ }
+
///
///
///
///
+ ///
///
- internal static Expression ConvertExpressionToNullableGetValueOrDefaultExpression(Expression expression)
+ internal static Expression ConvertExpressionToNullableValue(Expression expression)
{
- if (Nullable.GetUnderlyingType(expression.Type) != null)
+ if (Nullable.GetUnderlyingType(expression.Type) is { } underlyingType)
{
- var underlyingType = TypeCache.Get(expression.Type).GetUnderlyingType();
- var method = expression.Type.GetMethod("GetValueOrDefault", new Type[] { underlyingType });
- return Expression.Call(expression, method, Expression.Default(underlyingType));
+ return Expression.Property(expression, nameof(Nullable.Value));
}
return expression;
}
@@ -561,7 +577,7 @@ internal static Expression ConvertExpressionToNullableGetValueOrDefaultExpressio
{
if (Nullable.GetUnderlyingType(expression.Type) != null)
{
- var converted = converter(ConvertExpressionToNullableGetValueOrDefaultExpression(expression));
+ var converted = converter(ConvertExpressionToNullableValue(expression));
var nullableType = typeof(Nullable<>).MakeGenericType(converted.Type);
return Expression.Condition(
Expression.Property(expression, nameof(Nullable.HasValue)),
@@ -594,7 +610,7 @@ internal static Expression ConvertExpressionToNullableValueExpression(Expression
///
///
internal static Expression ConvertExpressionToGuidToStringExpression(Expression expression) =>
- Expression.Call(ConvertExpressionToNullableGetValueOrDefaultExpression(expression), StaticType.Guid.GetMethod("ToString", Array.Empty()));
+ Expression.Call(ConvertExpressionToNullableValue(expression), StaticType.Guid.GetMethod("ToString", Array.Empty()));
///
///
@@ -602,7 +618,7 @@ internal static Expression ConvertExpressionToGuidToStringExpression(Expression
///
///
internal static Expression ConvertExpressionToStringToGuidExpression(Expression expression) =>
- Expression.New(StaticType.Guid.GetConstructor(new[] { StaticType.String }), ConvertExpressionToNullableGetValueOrDefaultExpression(expression));
+ Expression.New(StaticType.Guid.GetConstructor(new[] { StaticType.String }), ConvertExpressionToNullableValue(expression));
///
///
@@ -611,7 +627,7 @@ internal static Expression ConvertExpressionToStringToGuidExpression(Expression
///
internal static Expression ConvertExpressionToTimeSpanToDateTimeExpression(Expression expression) =>
Expression.New(StaticType.DateTime.GetConstructor(new[] { StaticType.Int64 }),
- ConvertExpressionToNullableGetValueOrDefaultExpression(ConvertExpressionToTimeSpanTicksExpression(expression)));
+ ConvertExpressionToNullableValue(ConvertExpressionToTimeSpanTicksExpression(expression)));
///
///
@@ -619,7 +635,7 @@ internal static Expression ConvertExpressionToTimeSpanToDateTimeExpression(Expre
///
///
internal static Expression ConvertExpressionToDateTimeToTimeSpanExpression(Expression expression) =>
- ConvertExpressionToNullableGetValueOrDefaultExpression(ConvertExpressionToDateTimeTimeOfDayExpression(expression));
+ ConvertExpressionToNullableValue(ConvertExpressionToDateTimeTimeOfDayExpression(expression));
#if NET6_0_OR_GREATER
///
///
@@ -678,38 +694,89 @@ internal static Expression ConvertExpressionToDateTimeFromDateOnlyExpression(Exp
internal static Expression ConvertExpressionToSystemConvertExpression(Expression expression,
Type toType)
{
- if (TypeCache.Get(expression.Type).GetUnderlyingType() == toType)
+ var fromType = expression.Type;
+ var underlyingFromType = TypeCache.Get(fromType).GetUnderlyingType();
+ var underlyingToType = TypeCache.Get(toType).GetUnderlyingType();
+
+ if (fromType == toType)
{
return expression;
}
// Identify
- if (toType.IsAssignableFrom(expression.Type))
+ if (underlyingToType.IsAssignableFrom(fromType))
{
- return ConvertExpressionToTypeExpression(expression, toType);
+ return ConvertExpressionToTypeExpression(expression, underlyingToType);
}
+ var result = ConvertExpressionToNullableValue(expression);
+
// Convert.To()
- var methodInfo = GetSystemConvertToTypeMethod(expression.Type, toType);
- if (methodInfo != null)
+ if (underlyingFromType.IsEnum)
{
- return Expression.Call(methodInfo, ConvertExpressionToNullableGetValueOrDefaultExpression(expression));
- }
+ if (underlyingToType == StaticType.String)
+ {
+ result = Expression.Call(result, nameof(ToString), Array.Empty());
+ }
+ else if (underlyingToType.IsPrimitive &&
+ (underlyingToType) == StaticType.Int16
+ || underlyingToType == StaticType.Int32
+ || underlyingToType == StaticType.Int64
+ || underlyingToType == StaticType.Byte
+ || underlyingToType == StaticType.UInt16
+ || underlyingToType == StaticType.UInt32
+ || underlyingToType == StaticType.UInt64
+ || underlyingToType == StaticType.SByte)
+ {
+ result = Expression.Convert(result, Enum.GetUnderlyingType(underlyingFromType));
- // Convert.ChangeType
- methodInfo = GetSystemConvertChangeTypeMethod(toType);
- if (methodInfo != null)
+ if (result.Type != underlyingToType)
+ result = Expression.Convert(result, underlyingToType);
+ }
+ else
+ return result; // Will fail
+ }
+ else if (GetSystemConvertToTypeMethod(underlyingFromType, underlyingToType) is { } methodInfo)
{
- expression = ConvertExpressionToNullableGetValueOrDefaultExpression(expression);
- return Expression.Call(methodInfo, new Expression[]
+ result = Expression.Call(methodInfo, result);
+ }
+ else if (GetSystemConvertChangeTypeMethod(underlyingToType) is { } systemChangeType)
+ {
+ result = Expression.Call(systemChangeType, new Expression[]
{
- ConvertExpressionToTypeExpression(expression, StaticType.Object),
- Expression.Constant(TypeCache.Get(toType).GetUnderlyingType())
+ ConvertExpressionToTypeExpression(result, StaticType.Object),
+ Expression.Constant(TypeCache.Get(underlyingToType).GetUnderlyingType())
});
}
+ else
+ {
+ return result; // Will fail!
+ }
+
+ // Do we need manual NULL handling?
+ if ((!underlyingToType.IsValueType || underlyingToType != toType)
+ && (!underlyingFromType.IsValueType || underlyingFromType != fromType))
+ {
+ Expression condition;
+ if (underlyingFromType != fromType)
+ {
+ // E.g. Nullable -> string
+ condition = Expression.Property(expression, nameof(Nullable.HasValue));
+ }
+ else
+ {
+ // E.g. String -> Nullable
+ condition = Expression.NotEqual(expression, Expression.Constant(null, expression.Type));
+ }
+
+ return Expression.Condition(
+ condition,
+ (result.Type != toType) ? Expression.Convert(result, toType) : result,
+ Expression.Constant(null, toType));
+ }
// Return
- return expression;
+ return result;
}
///
@@ -745,17 +812,21 @@ internal static Expression ConvertExpressionToEnumExpression(Expression expressi
internal static Expression ConvertExpressionToEnumExpressionForString(Expression expression,
Type toEnumType)
{
- var trueExpression = GetEnumParseExpression(expression, toEnumType, true);
- if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic)
- {
- var isDefinedExpression = GetEnumIsDefinedExpression(expression, toEnumType);
- var falseExpression = ConvertExpressionToTypeExpression(Expression.Default(toEnumType), StaticType.Object);
- return Expression.Condition(isDefinedExpression, trueExpression, falseExpression);
- }
- else
- {
- return trueExpression;
- }
+ var checkMethod = (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic || GlobalConfiguration.Options.EnumHandling == EnumHandling.Cast || toEnumType.GetCustomAttribute() != null)
+ ? GetEnumParseNullMethod()
+ : GetEnumParseNullDefinedMethod();
+
+ return Expression.Coalesce(
+ Expression.Call(checkMethod.MakeGenericMethod(toEnumType), expression),
+
+ (GlobalConfiguration.Options.EnumHandling == EnumHandling.UseDefault)
+ ? Expression.Default(toEnumType)
+ : Expression.Throw(Expression.New(
+ typeof(ArgumentOutOfRangeException).GetConstructor(new[] { StaticType.String, StaticType.Object, StaticType.String }),
+ Expression.Constant("value"),
+ expression,
+ Expression.Constant($"Invalid value for {toEnumType.Name}")),
+ toEnumType));
}
///
@@ -767,14 +838,28 @@ internal static Expression ConvertExpressionToEnumExpressionForString(Expression
internal static Expression ConvertExpressionToEnumExpressionForNonString(Expression expression,
Type toEnumType)
{
- if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic)
+ if (GlobalConfiguration.Options.ConversionType == ConversionType.Automatic || GlobalConfiguration.Options.EnumHandling == EnumHandling.Cast)
{
return Expression.Convert(expression, toEnumType);
}
else
{
- return ConvertExpressionToEnumExpressionForString(
- GetEnumGetNameExpression(expression, toEnumType), toEnumType);
+ // Handle long/short to enum and/or non integer based enums
+ if (expression.Type != Enum.GetUnderlyingType(toEnumType))
+ expression = Expression.Convert(expression, Enum.GetUnderlyingType(toEnumType));
+
+ return Expression.Condition(
+ GetEnumIsDefinedExpression(expression, toEnumType), // Check if the value is defined
+ Expression.Convert(expression, toEnumType), // Cast to enum
+ GlobalConfiguration.Options.EnumHandling switch
+ {
+ EnumHandling.UseDefault => Expression.Default(toEnumType),
+ EnumHandling.ThrowError => Expression.Throw(Expression.New(typeof(InvalidEnumArgumentException).GetConstructor(new[] { StaticType.String, StaticType.Int32, StaticType.Type }),
+ new Expression[] { Expression.Constant("value"), Expression.Convert(expression, StaticType.Int32), Expression.Constant(toEnumType) }),
+ toEnumType
+ ),
+ _ => throw new InvalidEnumArgumentException("EnumHandling set to invalid value")
+ }); // Default value for undefined
}
}
@@ -913,12 +998,13 @@ internal static Expression ConvertExpressionToNullableExpression(Expression expr
///
///
///
- ///
+ ///
///
internal static Expression ConvertExpressionWithAutomaticConversion(Expression expression,
- Type toType)
+ Type trueToType)
{
var fromType = TypeCache.Get(expression.Type).GetUnderlyingType();
+ var toType = TypeCache.Get(trueToType)?.GetUnderlyingType();
// Guid to String
if (fromType == StaticType.Guid && toType == StaticType.String)
@@ -959,7 +1045,7 @@ internal static Expression ConvertExpressionWithAutomaticConversion(Expression e
// Others
else
{
- expression = ConvertExpressionToSystemConvertExpression(expression, toType);
+ expression = ConvertExpressionToSystemConvertExpression(expression, trueToType);
}
// Return
@@ -1136,26 +1222,6 @@ internal static Expression ConvertExpressionToClassHandlerSetExpression(Expressi
#region Common
- ///
- ///
- ///
- ///
- ///
- ///
- ///
- internal static Expression GetEnumParseExpression(Expression expression,
- Type enumType,
- bool ignoreCase)
- {
- var parameters = new Expression[]
- {
- Expression.Constant(enumType),
- expression,
- Expression.Constant(ignoreCase)
- };
- return Expression.Call(GetEnumParseMethod(), parameters);
- }
-
///
///
///
@@ -1332,7 +1398,7 @@ internal static Expression GetClassPropertyParameterInfoIsDbNullFalseValueExpres
{
try
{
- valueExpression = ConvertExpressionWithAutomaticConversion(valueExpression, targetTypeUnderlyingType);
+ valueExpression = ConvertExpressionWithAutomaticConversion(valueExpression, targetType);
}
catch (Exception ex)
{
@@ -1611,7 +1677,7 @@ internal static Expression GetEntityInstancePropertyValueExpression(Expression e
// Target type
var handlerInstance = classProperty.GetPropertyHandler() ?? PropertyHandlerCache.Get
public static Type DateTimeOffset => typeof(DateTimeOffset);
-
- #if NET6_0_OR_GREATER
+
+#if NET6_0_OR_GREATER
///
/// Gets a type of the .NET CLR type.
///
@@ -105,8 +105,8 @@ internal static class StaticType
/// Gets a type of the .NET CLR type.
///
public static Type TimeOnly => typeof(TimeOnly);
- #endif
-
+#endif
+
///
/// Gets a type of the .NET CLR type.
///
@@ -376,5 +376,10 @@ internal static class StaticType
/// Gets a type of the .NET CLR type.
///
public static Type UInt64 => typeof(ulong);
+
+ ///
+ /// Gets a type of the .NET CLR type.
+ ///
+ public static Type SByte => typeof(sbyte);
}
}
diff --git a/RepoDb.Core/RepoDb/Trace/CancellableTraceLog.cs b/RepoDb.Core/RepoDb/Trace/CancellableTraceLog.cs
index 5670adf0d..146ae9bc5 100644
--- a/RepoDb.Core/RepoDb/Trace/CancellableTraceLog.cs
+++ b/RepoDb.Core/RepoDb/Trace/CancellableTraceLog.cs
@@ -74,11 +74,11 @@ public void Cancel(bool throwException = true)
///
/// The string representation of the current object.
public override string ToString() =>
- $"SessiontId: {SessionId}\n" +
+ $"SessionId: {SessionId}\n" +
$"Key: {Key}\n" +
$"Statement: {Statement}\n" +
- $"StarTime (Ticks): {StartTime.Ticks}\n" +
- $"Parameters: {(Parameters?.Any() == true ? string.Join(", ", Parameters.ToArray().Select(param => $"({param.ParameterName}={param.Value})")) : "No Parameters")}";
+ $"StartTime (Ticks): {StartTime.Ticks}\n" +
+ $"Parameters: {(Parameters?.Any() == true ? string.Join(", ", Parameters.ToArray().Select(param => $"({param.ParameterName}={(param.Value is DBNull ? "DBNull" : param.Value)})")) : "No Parameters")}";
#endregion
}
diff --git a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/RepoDb.PostgreSql.BulkOperations.IntegrationTests.csproj b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/RepoDb.PostgreSql.BulkOperations.IntegrationTests.csproj
index f34dd3ade..739198bb4 100644
--- a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/RepoDb.PostgreSql.BulkOperations.IntegrationTests.csproj
+++ b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/RepoDb.PostgreSql.BulkOperations.IntegrationTests.csproj
@@ -1,28 +1,24 @@
-
net6.0;net7.0;net8.0
false
+ true
+ true
+ true
-
-
-
-
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
diff --git a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/Setup/Database.cs b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/Setup/Database.cs
index 3fd17a1c4..ee29fe7b5 100644
--- a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/Setup/Database.cs
+++ b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.IntegrationTests/Setup/Database.cs
@@ -1,5 +1,5 @@
-using Npgsql;
-using System;
+using System;
+using Npgsql;
namespace RepoDb.IntegrationTests.Setup
{
@@ -13,12 +13,20 @@ public static class Database
///
public static void Initialize()
{
- // Set the connection string
- ConnectionStringForPosgres = Environment.GetEnvironmentVariable("REPODB_CONSTR_POSTGRESDB", EnvironmentVariableTarget.Process) ??
- "Server=127.0.0.1;Port=5432;Database=postgres;User Id=postgres;Password=Password123;";
- ConnectionStringForRepoDb = Environment.GetEnvironmentVariable("REPODB_CONSTR", EnvironmentVariableTarget.Process)??
- "Server=127.0.0.1;Port=5432;Database=RepoDb;User Id=postgres;Password=Password123;";
-
+ // Master connection
+ ConnectionStringForPostgres =
+ Environment.GetEnvironmentVariable("REPODB_POSTGRESQL_CONSTR_POSTGRESDB")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR_POSTGRESDB")
+ //?? "Server=127.0.0.1;Port=45432;Database=postgres;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;" // Docker test configuration
+ ?? "Server=127.0.0.1;Port=5432;Database=postgres;User Id=postgres;Password=Password123;";
+
+ // RepoDb connection
+ ConnectionStringForRepoDb =
+ Environment.GetEnvironmentVariable("REPODB_POSTGRESQL_CONSTR_BULK")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR_BULK")
+ //?? "Server=127.0.0.1;Port=45432;Database=RepoDbBulk;User Id=postgres;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;" // Docker test configuration
+ ?? "Server=127.0.0.1;Port=5432;Database=RepoDbBulk;User Id=postgres;Password=Password123;";
+
// Initialize PostgreSql
GlobalConfiguration.Setup().UsePostgreSql();
@@ -32,7 +40,7 @@ public static void Initialize()
///
/// Gets or sets the connection string to be used for Postgres database.
///
- public static string ConnectionStringForPosgres { get; private set; }
+ public static string ConnectionStringForPostgres { get; private set; }
///
/// Gets or sets the connection string to be used.
@@ -46,12 +54,12 @@ public static void Initialize()
///
public static void CreateDatabase()
{
- using (var connection = new NpgsqlConnection(ConnectionStringForPosgres))
+ using (var connection = new NpgsqlConnection(ConnectionStringForPostgres))
{
- var recordCount = connection.ExecuteScalar("SELECT COUNT(*) FROM pg_database WHERE datname = 'RepoDb';");
+ var recordCount = connection.ExecuteScalar("SELECT COUNT(*) FROM pg_database WHERE datname = 'RepoDbBulk';");
if (recordCount <= 0)
{
- connection.ExecuteNonQuery(@"CREATE DATABASE ""RepoDb""
+ connection.ExecuteNonQuery(@"CREATE DATABASE ""RepoDbBulk""
WITH OWNER = ""postgres""
ENCODING = ""UTF8""
CONNECTION LIMIT = -1;");
diff --git a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.csproj b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.csproj
index 5050e1ebf..23f304422 100644
--- a/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.csproj
+++ b/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations/RepoDb.PostgreSql.BulkOperations.csproj
@@ -1,39 +1,20 @@
-
-
- RepoDb.PostgreSql.BulkOperations
- netstandard2.0;net6.0;net7.0;net8.0
- 0.0.1
- 0.0.1
- 0.0.1
- An extension library that contains the official Bulk Operations of RepoDb for PostgreSQL.
- orm hybrid-orm micro-orm postgresql bulkoperations
- https://github.com/mikependon/RepoDb/tree/master/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations
- http://repodb.net/release/postgresqlbulk
- true
- true
- https://repodb.net/tutorial/get-started-postgresql
-
-
-
-
-
-
-
-
-
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ RepoDb.PostgreSql.BulkOperations
+ netstandard2.0;net6.0;net7.0;net8.0
+ annotations
+ An extension library that contains the official Bulk Operations of RepoDb for PostgreSQL.
+ orm hybrid-orm micro-orm postgresql bulkoperations
+ https://github.com/mikependon/RepoDb/tree/master/RepoDb.Extensions/RepoDb.PostgreSql.BulkOperations
+ http://repodb.net/release/postgresqlbulk
+ https://repodb.net/tutorial/get-started-postgresql
+
+
+
+
+
+
+
+
+
diff --git a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/RepoDb.SqlServer.BulkOperations.IntegrationTests.csproj b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/RepoDb.SqlServer.BulkOperations.IntegrationTests.csproj
index 780812c0d..7f376eda0 100644
--- a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/RepoDb.SqlServer.BulkOperations.IntegrationTests.csproj
+++ b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/RepoDb.SqlServer.BulkOperations.IntegrationTests.csproj
@@ -1,10 +1,11 @@
-
- net6.0;net7.0;net8.0
+ net6.0;net7.0;net8.0
false
+ true
+ true
+ true
-
@@ -19,21 +20,16 @@
-
-
-
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
+
\ No newline at end of file
diff --git a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/Setup/Database.cs b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/Setup/Database.cs
index 44f9d7eda..082dc7159 100644
--- a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/Setup/Database.cs
+++ b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations.IntegrationTests/Setup/Database.cs
@@ -1,6 +1,6 @@
-using Microsoft.Data.SqlClient;
+using System;
+using Microsoft.Data.SqlClient;
using RepoDb.SqlServer.BulkOperations.IntegrationTests.Models;
-using System;
namespace RepoDb.IntegrationTests.Setup
{
@@ -15,15 +15,23 @@ public static class Database
public static void Initialize()
{
// Master connection
- ConnectionStringForMaster = Environment.GetEnvironmentVariable("REPODB_CONSTR_MASTER", EnvironmentVariableTarget.Process) ??
- @"Server=(local);Database=master;Integrated Security=SSPI;TrustServerCertificate=True;";
+ ConnectionStringForMaster =
+ Environment.GetEnvironmentVariable("REPODB_SQLSERVER_CONSTR_MASTER")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR_MASTER")
+ // ?? @"Server=tcp:127.0.0.1,41433;Database=master;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;" // Docker Test Configuration
+ ?? @"Server=(local);Database=master;Integrated Security=SSPI;TrustServerCertificate=True;";
// RepoDb connection
- ConnectionStringForRepoDb = Environment.GetEnvironmentVariable("REPODB_CONSTR", EnvironmentVariableTarget.Process) ??
- @"Server=(local);Database=RepoDb;Integrated Security=SSPI;TrustServerCertificate=True;";
+ ConnectionStringForRepoDb =
+ Environment.GetEnvironmentVariable("REPODB_SQLSERVER_CONSTR_REPODBTEST")
+ ?? Environment.GetEnvironmentVariable("REPODB_CONSTR")
+ // ?? @"Server=tcp:127.0.0.1,41433;Database=RepoDbTest;User ID=sa;Password=ddd53e85-b15e-4da8-91e5-a7d3b00a0ab2;TrustServerCertificate=True;" // Docker Test Configuration
+ ?? @"Server=(local);Database=RepoDbTest;Integrated Security=SSPI;TrustServerCertificate=True;";
// Initialize the SqlServer
- GlobalConfiguration.Setup().UseSqlServer();
+ GlobalConfiguration
+ .Setup()
+ .UseSqlServer();
// Create the database first
CreateDatabase();
@@ -49,9 +57,9 @@ public static void Initialize()
///
public static void CreateDatabase()
{
- var commandText = @"IF (NOT EXISTS(SELECT * FROM sys.databases WHERE name = 'RepoDb'))
+ var commandText = @"IF (NOT EXISTS(SELECT * FROM sys.databases WHERE name = 'RepoDbTest'))
BEGIN
- CREATE DATABASE [RepoDb];
+ CREATE DATABASE [RepoDbTest];
END";
using (var connection = new SqlConnection(ConnectionStringForMaster).EnsureOpen())
{
diff --git a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkDelete.cs b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkDelete.cs
index 0d0fbd7ea..bf072bd11 100644
--- a/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkDelete.cs
+++ b/RepoDb.Extensions/RepoDb.SqlServer.BulkOperations/RepoDb.SqlServer.BulkOperations/Base/BulkDelete.cs
@@ -1,6 +1,4 @@
-using RepoDb.Extensions;
-using RepoDb.SqlServer.BulkOperations;
-using System;
+using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
@@ -8,6 +6,9 @@
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Data.SqlClient;
+using RepoDb.Extensions;
+using RepoDb.Interfaces;
+using RepoDb.SqlServer.BulkOperations;
namespace RepoDb
{
@@ -26,15 +27,17 @@ public static partial class SqlConnectionExtension
///
///
///
+ ///
///
internal static int BulkDeleteInternalBase(SqlConnection connection,
string tableName,
IEnumerable