diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index ef9ecb40c2c..ee996697750 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,13 +3,13 @@ "isRoot": true, "tools": { "csharpasyncgenerator.tool": { - "version": "0.21.1", + "version": "0.22.0", "commands": [ "async-generator" ] }, "gitreleasemanager.tool": { - "version": "0.11.0", + "version": "0.18.0", "commands": [ "dotnet-gitreleasemanager" ] diff --git a/.editorconfig b/.editorconfig index cdafebe60ab..15901d7cb25 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,6 +2,7 @@ root=true [*] insert_final_newline = true +charset = utf-8 [*.cs] indent_style = tab @@ -15,6 +16,18 @@ csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_between_query_expression_clauses = true +dotnet_diagnostic.NUnit1032.severity = suggestion +dotnet_diagnostic.NUnit1028.severity = none +dotnet_diagnostic.NUnit2045.severity = none +# Consider using the constraint model, Assert.That +dotnet_diagnostic.NUnit2005.severity = suggestion +dotnet_diagnostic.NUnit2006.severity = suggestion +dotnet_diagnostic.NUnit2015.severity = suggestion +dotnet_diagnostic.NUnit2031.severity = suggestion +dotnet_diagnostic.NUnit2049.severity = suggestion +# The SameAs constraint always fails on value types as the actual and the expected value cannot be the same reference +dotnet_diagnostic.NUnit2040.severity = suggestion + [*.xsd] indent_style = tab @@ -22,21 +35,10 @@ indent_style = tab indent_style = space indent_size = 2 -[*.xml] +[{*.xml,*.csproj,*.vbproj}] indent_style = space indent_size = 2 - -[*.csproj] -indent_style = space -indent_size = 2 - -[*.vbproj] -indent_style = space -indent_size = 2 - -[*.cshtml] -indent_style = space -indent_size = 4 +ij_xml_space_inside_empty_tag = true [*.g] indent_style = tab diff --git a/.github/renovate.json b/.github/renovate.json index 3db573fccf1..d788bcd927f 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,7 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ - "config:base" + "config:recommended" ], "configMigration": true, "pruneStaleBranches": false, @@ -15,26 +15,22 @@ ], "packageRules": [ { - "matchPackagePrefixes": [ - "NUnit" + "matchSourceUrls": [ + "https://github.com/nunit/nunit" ], "groupName": "NUnit" - }, + }, { + "groupName": "Oracle.ManagedDataAccess", "matchPackageNames": [ - "Microsoft.AspNetCore", - "Microsoft.AspNetCore.Mvc", - "Microsoft.AspNetCore.Mvc.Razor.ViewCompilation", - "Microsoft.AspNetCore.StaticFiles" - ], - "groupName": "Microsoft.AspNetCore 2.0", - "allowedVersions": "~2.1.0" + "Oracle.ManagedDataAccess{/,}**" + ] }, { - "matchPackagePrefixes": [ - "Oracle.ManagedDataAccess" - ], - "groupName": "Oracle.ManagedDataAccess" + "groupName": "NHibernate.Caches", + "matchPackageNames": [ + "NHibernate.Caches{/,}**" + ] } ] } diff --git a/.github/workflows/GenerateAsyncCode.yml b/.github/workflows/GenerateAsyncCode.yml index 2a28aa4e5dd..38b0c0442de 100644 --- a/.github/workflows/GenerateAsyncCode.yml +++ b/.github/workflows/GenerateAsyncCode.yml @@ -5,23 +5,23 @@ on: paths: - '**.cs' -permissions: {} +permissions: + contents: write jobs: generate-async: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} - token: ${{ secrets.NHIBERNATE_BOT_TOKEN }} - name: Setup .NET - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: - dotnet-version: 6.0.x + dotnet-version: 8.0.x - name: Generate Async code run: | diff --git a/.github/workflows/NetCoreTests.yml b/.github/workflows/NetCoreTests.yml index c88177b97e9..093c1e99534 100644 --- a/.github/workflows/NetCoreTests.yml +++ b/.github/workflows/NetCoreTests.yml @@ -7,47 +7,71 @@ jobs: strategy: fail-fast: false matrix: + DB: [SQLite] + OS: [ubuntu-latest, windows-latest, macos-13] include: - DB: SqlServer2008 CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" + OS: ubuntu-latest + DB_INIT: | + docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; + - DB: SqlServer2008-MicrosoftDataSqlClientDriver + CONNECTION_STRING: "Server=localhost;initial catalog=nhibernate;User Id=sa;Password=P@ssw0rd;packet size=4096;" + OS: ubuntu-latest DB_INIT: | docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=P@ssw0rd" -e "MSSQL_PID=Express" -p 1433:1433 -d --name sqlexpress mcr.microsoft.com/mssql/server:2019-latest; - DB: PostgreSQL CONNECTION_STRING: "Host=localhost;Username=nhibernate;Password=nhibernate;Database=nhibernate;Enlist=true;" + OS: ubuntu-latest + DB_INIT: | + docker run -d -e POSTGRES_USER=nhibernate -e POSTGRES_PASSWORD=nhibernate -e POSTGRES_DB=nhibernate -p 5432:5432 postgres:13 + - DB: PostgreSQL + CONNECTION_STRING: "Host=localhost;Username=postgres;Password=nhibernate;Database=nhibernate;Enlist=true;" + OS: windows-latest DB_INIT: | - docker run -d -e POSTGRES_USER=nhibernate -e POSTGRES_PASSWORD=nhibernate -e POSTGRES_DB=nhibernate -p 5432:5432 postgres:13 + choco install postgresql13 --no-progress --params '/Password:nhibernate' + Add-Content -Path 'C:\Program Files\PostgreSQL\13\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" + Start-Service 'postgresql-x64-13' - DB: Firebird CONNECTION_STRING: "DataSource=localhost;Database=nhibernate;User=SYSDBA;Password=nhibernate;charset=utf8;" + OS: ubuntu-latest DB_INIT: | docker run --name firebird -e EnableWireCrypt=true -e FIREBIRD_USER=nhibernate -e FIREBIRD_PASSWORD=nhibernate -e ISC_PASSWORD=nhibernate -e FIREBIRD_DATABASE=nhibernate -p 3050:3050 -d jacobalberty/firebird:v3.0 - DB: Firebird4 CONNECTION_STRING: "DataSource=localhost;Database=nhibernate;User=SYSDBA;Password=nhibernate;charset=utf8;" + OS: ubuntu-latest DB_INIT: | docker run --name firebird -e EnableWireCrypt=true -e FIREBIRD_USER=nhibernate -e FIREBIRD_PASSWORD=nhibernate -e ISC_PASSWORD=nhibernate -e FIREBIRD_DATABASE=nhibernate -p 3050:3050 -d jacobalberty/firebird:v4.0 - DB: MySQL CONNECTION_STRING: "Server=localhost;Uid=root;Password=nhibernate;Database=nhibernate;Old Guids=True;SslMode=none;" + OS: ubuntu-latest DB_INIT: | sudo service mysql stop docker run --name mysql -e MYSQL_ROOT_PASSWORD=nhibernate -e MYSQL_USER=nhibernate -e MYSQL_PASSWORD=nhibernate -e MYSQL_DATABASE=nhibernate -p 3306:3306 --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 -d mysql:5.7 mysqld --lower_case_table_names=1 --character-set-server=utf8 --collation-server=utf8_general_ci - DB: Oracle CONNECTION_STRING: "User ID=nhibernate;Password=nhibernate;Metadata Pooling=false;Self Tuning=false;Data Source=(DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = XEPDB1)))" + OS: ubuntu-latest DB_INIT: | docker run -d -p 1521:1521 -e APP_USER=nhibernate -e APP_USER_PASSWORD=nhibernate -e ORACLE_PASSWORD=nhibernate gvenzl/oracle-xe:21-slim - - DB: SQLite - runs-on: ubuntu-latest + runs-on: ${{matrix.OS}} continue-on-error: ${{matrix.ALLOW_FAILURE == true}} env: LANG: en-US.UTF-8 #default POSIX locale doesn't support ignore case comparisons - name: ${{matrix.DB}} + name: ${{matrix.DB}} - ${{matrix.OS}} steps: - name: Set up ${{matrix.DB}} run: ${{matrix.DB_INIT}} - - uses: actions/checkout@v3 - - name: Setup .NET - uses: actions/setup-dotnet@v3 + + - name: Set up .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.x + + - name: Checkout + uses: actions/checkout@v4 with: - dotnet-version: 6.0.x + show-progress: false - name: Build and Test run: | diff --git a/README.md b/README.md index 8da992df161..6290ebbaa94 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Nightly Development Builds -------------------------- The quickest way to get the latest development build of NHibernate is to add it to your project using -NuGet from MyGet feed (). +NuGet from Cloudsmith feed (). In order to make life a little bit easier you can register the package source in the NuGet.Config file in the top folder of your project, similar to the following. @@ -35,11 +35,18 @@ file in the top folder of your project, similar to the following. - + ``` +Package repository hosting is graciously provided by [Cloudsmith](https://cloudsmith.com). +Cloudsmith is the only fully hosted, cloud-native, universal package management solution, that +enables your organization to create, store and share packages in any format, to any place, with total +confidence. + +[![Hosted By: Cloudsmith](https://img.shields.io/badge/OSS%20hosting%20by-cloudsmith-blue?logo=cloudsmith&style=flat-square)](https://cloudsmith.com) + Community Forums ---------------- diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..50416634993 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,16 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 5.5.x | :white_check_mark: | +| 5.4.x | :white_check_mark: | +| < 5.4 | :x: | + +## Reporting a Vulnerability + +**Please do NOT report security vulnerabilities through public GitHub issues.** + +Instead, please submit vulnerabilities using this [form](https://github.com/nhibernate/nhibernate-core/security/advisories/new). +If the issue is confirmed, we will try to release a patch version as soon as possible depending on complexity. diff --git a/ShowBuildMenu.sh b/ShowBuildMenu.sh index cb133384784..67d44f121dd 100755 --- a/ShowBuildMenu.sh +++ b/ShowBuildMenu.sh @@ -172,8 +172,8 @@ testSetupMenu() { } testRun(){ - dotnet test ./src/NHibernate.Test/NHibernate.Test.csproj -f net6.0 - dotnet test ./src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj -f net6.0 + dotnet test ./src/NHibernate.Test/NHibernate.Test.csproj -f net8.0 + dotnet test ./src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj -f net8.0 mainMenu } diff --git a/Tools/BuildTool/BuildTool.csproj b/Tools/BuildTool/BuildTool.csproj index cdc734cce53..b3587f9d5a3 100644 --- a/Tools/BuildTool/BuildTool.csproj +++ b/Tools/BuildTool/BuildTool.csproj @@ -1,6 +1,6 @@  Exe - net6.0 + net8.0 \ No newline at end of file diff --git a/Tools/packages.csproj b/Tools/packages.csproj index 9bd32fe4d05..aa216b9b04b 100644 --- a/Tools/packages.csproj +++ b/Tools/packages.csproj @@ -11,7 +11,7 @@ - + diff --git a/appveyor.yml b/appveyor.yml index a73e841f7e6..e497e3469dc 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -4,13 +4,12 @@ environment: matrix: - DB: SqlServer2008 CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; - - DB: PostgreSQL - CONNECTION_STRING: Host=localhost;Port=5432;Username=postgres;Password=Password12!;Database=nhibernate;Enlist=true; + - DB: SqlServer2008-MicrosoftDataSqlClientDriver + CONNECTION_STRING: Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate; - DB: Firebird - DB: Firebird4 - DB: MySQL CONNECTION_STRING: Server=127.0.0.1;Uid=root;Pwd=Password12!;Database=nhibernate;Old Guids=True;SslMode=none;CharSet=utf8; - - DB: SQLite init: # Required for having windows endlines in sources zip - git config --global core.autocrlf true @@ -61,19 +60,16 @@ before_test: Pop-Location } 'MySQL' { - Start-Service 'MySQL57' + Start-Service 'MySQL80' # Create nhibernate database (not handled by NHibernate.TestDatabaseSetup.dll) $env:MYSQL_PWD = 'Password12!' - & 'C:\Program Files\MySQL\MySQL Server 5.7\bin\mysql' -e 'CREATE DATABASE nhibernate CHARACTER SET utf8 COLLATE utf8_general_ci;' --user=root + & 'C:\Program Files\MySQL\MySQL Server 8.0\bin\mysql' -e 'CREATE DATABASE nhibernate CHARACTER SET utf8 COLLATE utf8_general_ci;' --user=root } 'Odbc' { Start-Service 'MSSQL$SQL2017' } - 'PostgreSQL' { - # Enable prepared transactions - Add-Content -Path 'C:\Program Files\PostgreSQL\10\data\postgresql.conf' -Value "`r`nmax_prepared_transactions = 100" - Start-Service 'postgresql-x64-10' - } 'SqlServer2008' { Start-Service 'MSSQL$SQL2017' } + 'SqlServer2008-MicrosoftDataSqlClientDriver' { Start-Service 'MSSQL$SQL2017' } 'SqlServer2012' { Start-Service 'MSSQL$SQL2017' } + 'SqlServer2012-MicrosoftDataSqlClientDriver' { Start-Service 'MSSQL$SQL2017' } 'SQLite' { } } test_script: diff --git a/build-common/NHibernate.props b/build-common/NHibernate.props index 5575d231ce4..c2676d0cd85 100644 --- a/build-common/NHibernate.props +++ b/build-common/NHibernate.props @@ -2,11 +2,11 @@ - 5.5 + 5.6 0 dev - 9.0 + 12.0 $(NhVersion).$(VersionPatch) $(VersionSuffix).$(BuildNumber) @@ -14,14 +14,17 @@ $(VersionPrefix).$(BuildNumber) $(VersionPrefix).0 - net48;net6.0 - net461;net48;netcoreapp2.0;netstandard2.0;netstandard2.1;net6.0 + net48;net8.0 + net461;net48;netcoreapp2.0;netstandard2.0;netstandard2.1;net6.0;net8.0 + 2.0.3 false true NETFX;$(DefineConstants) NETFX,$(DefineConstants) + $(NoWarn);NU1903 $(NoWarn);SYSLIB0011 + $(NoWarn);SYSLIB0011;SYSLIB0050;SYSLIB0051 NHibernate NHibernate.info diff --git a/build-common/teamcity-hibernate.cfg.xml b/build-common/teamcity-hibernate.cfg.xml index e8cb7f7e6dd..9cdad8f1e78 100644 --- a/build-common/teamcity-hibernate.cfg.xml +++ b/build-common/teamcity-hibernate.cfg.xml @@ -26,5 +26,7 @@ + + diff --git a/default.build b/default.build index c8020603e1c..2ee19e5a694 100644 --- a/default.build +++ b/default.build @@ -139,6 +139,26 @@ + + + + + + + + + + + + + + + + diff --git a/doc/reference/modules/basic_mapping.xml b/doc/reference/modules/basic_mapping.xml index 122def3f62f..2056bbe27a4 100644 --- a/doc/reference/modules/basic_mapping.xml +++ b/doc/reference/modules/basic_mapping.xml @@ -3919,7 +3919,8 @@ CultureInfo System.Globalization.CultureInfo - DbType.String - 5 chars for culture + DbType.String - 5 chars for culture by default; + can be modified by the length mapping attribute. Default when no type attribute specified. diff --git a/doc/reference/modules/configuration.xml b/doc/reference/modules/configuration.xml index 15656f556c1..7e590d4c9dd 100644 --- a/doc/reference/modules/configuration.xml +++ b/doc/reference/modules/configuration.xml @@ -871,6 +871,20 @@ var session = sessions.OpenSession(conn); + + + escape_backslash_in_strings + + + Indicates if the database needs to have backslash escaped in string literals. + The default value is dialect dependant. That is false for + most dialects. + + eg. + true | false + + + show_sql @@ -1050,8 +1064,8 @@ var session = sessions.OpenSession(conn); after scope disposal. This occurs when the transaction is distributed. This notably concerns ISessionImplementor.AfterTransactionCompletion(bool, ITransaction). NHibernate protects the session from being concurrently used by the code following the scope disposal - with a lock. To prevent any application freeze, this lock has a default timeout of five seconds. If the - application appears to require longer (!) running transaction completion events, this setting allows to + with a lock. To prevent any application freeze, this lock has a default timeout of one second. If the + application appears to require longer running transaction completion events, this setting allows to raise this timeout. -1 disables the timeout. @@ -1060,6 +1074,33 @@ var session = sessions.OpenSession(conn); + + + transaction.ignore_session_synchronization_failures + + + Whether session synchronisation failures occuring during finalizations of system transaction should be + ignored or not. false by default. + + When a system transaction terminates abnormaly, especially through timeouts, it may have its + completion events running on concurrent threads while the session is still performing some processing. + To prevent threading concurrency failures, NHibernate then wait for the session to end its processing, + up to transaction.system_completion_lock_timeout. If the session processing is still ongoing + afterwards, it will by default log an error, perform transaction finalization processing concurrently, + then throw a synchronization error. This setting allows to disable that later throw. + + + Disabling the throw can be useful if the used data provider has its own locking mechanism applied + during transaction completion, preventing the session to end its processing. It may then be safe to + ignore this synchronization failure. In case of threading concurrency failure, you may then need to + raise transaction.system_completion_lock_timeout. + + + eg. + true | false + + + transaction.auto_join @@ -1515,12 +1556,6 @@ in the parameter binding. NHibernate.Dialect.PostgreSQLDialect - - PostgreSQL - NHibernate.Dialect.PostgreSQLDialect - - - PostgreSQL 8.1 NHibernate.Dialect.PostgreSQL81Dialect diff --git a/doc/reference/modules/manipulating_data.xml b/doc/reference/modules/manipulating_data.xml index c65f9fe6ffe..c57952af1f9 100644 --- a/doc/reference/modules/manipulating_data.xml +++ b/doc/reference/modules/manipulating_data.xml @@ -838,9 +838,11 @@ sess.Lock(pk, LockMode.Upgrade);]]> It is possible to change the default behavior so that flush occurs less frequently. The FlushMode class defines three different modes: only flush at commit time (and only when the NHibernate ITransaction - API is used, or inside a transaction scope), flush automatically using the explained - routine (will only work inside an explicit NHibernate ITransaction or - inside a transaction scope), or never flush unless + API is used, or inside a transaction scope with a legacy option enabled - see + ), flush automatically using the explained + routine (will only work inside an explicit NHibernate ITransaction, or + inside a transaction scope with limitations for flushes on commit - see + ), or never flush unless Flush() is called explicitly. The last mode is useful for long running units of work, where an ISession is kept open and disconnected for a long time (see ). diff --git a/doc/reference/modules/nhibernate_caches.xml b/doc/reference/modules/nhibernate_caches.xml index 997b5ff1a0b..74877aec459 100644 --- a/doc/reference/modules/nhibernate_caches.xml +++ b/doc/reference/modules/nhibernate_caches.xml @@ -43,17 +43,6 @@ Several cache providers have been contributed by NHibernate users: - - NHibernate.Caches.Prevalence - - - Uses Bamboo.Prevalence as the cache provider. Open the - file Bamboo.Prevalence.license.txt for more information about its license; - you can also visit its website. This - provider is available for the .Net Framework only. Also see . - - - NHibernate.Caches.SysCache @@ -158,8 +147,7 @@ Choose the cache provider you want to use and copy its assembly in your assemblies directory. - (For example, NHibernate.Caches.Prevalence.dll or - NHibernate.Caches.SysCache.dll.) + (For example, NHibernate.Caches.SysCache.dll.) @@ -279,19 +267,6 @@ -
- Prevalence Cache Configuration - - There is only one configurable parameter: prevalenceBase. This is the directory on the - file system where the Prevalence engine will save data. It can be relative to the current directory or a - full path. If the directory doesn't exist, it will be created. - - - The prevalenceBase setting can only be set programmatically through the NHibernate - configuration object, by example with Configuration.SetProperty. - -
-
SysCache Configuration @@ -818,6 +793,14 @@ Extends NHibernate.Caches.StackExchangeRedis.DefaultRegionStrategy and uses an additional local memory cache for faster readings. The local caches are invalidated by using Redis pub/sub mechanism. This strategy should be used only for regions that have few write operations and a high expiration time. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + This strategy inherits additional settings from DefaultRegionStrategy and also has its own settings: cache.region_strategy.two_layer_cache.use_pipelining @@ -848,7 +831,16 @@ Extends NHibernate.Caches.StackExchangeRedis.FastRegionStrategy and uses an additional local memory cache for faster readings. The local caches are invalidated by using Redis pub/sub mechanism. This strategy does not support ICache.Clear operation and should be used only for regions that have - few write operations and a high expiration time. This strategy has additional settings: + few write operations and a high expiration time. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + + This strategy has additional settings: cache.region_strategy.fast_two_layer_cache.use_pipelining @@ -880,9 +872,16 @@ operation was performed. When two operations have the same DateTime.Ticks, then the client with the highest id wins. This strategy should be used only for regions that have few write operations and a high expiration time. It is recommended to use NHibernate.Caches.StackExchangeRedis.TwoLayerCacheRegionStrategy, when the instances where the strategy - would run are often restarted/recycled. In order to use this strategy a custom ICacheRegionStrategyFactory - has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a custom - RegionMemoryCacheBase implementation. This strategy has additional settings: + would run are often restarted/recycled. + + + In order to use this strategy a custom ICacheRegionStrategyFactory + has to be provided (see cache.region_strategy_factory setting), where the strategy is created with a + custom RegionMemoryCacheBase implementation. See the source of + NHibernate.Caches.StackExchangeRedis.Tests.CacheRegionStrategyFactory for an example. + + + This strategy has additional settings: cache.region_strategy.distributed_local_cache.use_pipelining diff --git a/doc/reference/modules/performance.xml b/doc/reference/modules/performance.xml index f44a5f6a9f8..2ac0cc800ba 100644 --- a/doc/reference/modules/performance.xml +++ b/doc/reference/modules/performance.xml @@ -709,13 +709,6 @@ using(var iter = session yes - - Prevalence Cache - NHibernate.Caches.Prevalence.PrevalenceCacheProvider, NHibernate.Caches.Prevalence - memory, disk - - yes - @@ -877,12 +870,6 @@ using(var iter = session yes yes - - PrevalenceCache - yes - yes - yes - diff --git a/global.json b/global.json index 6ecdd6167f9..391ba3c2a30 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.101", + "version": "8.0.100", "rollForward": "latestFeature" } } diff --git a/lib/teamcity/postgresql/postgresql_installation.txt b/lib/teamcity/postgresql/postgresql_installation.txt index b5deb92b10a..28e90cc7d5a 100644 --- a/lib/teamcity/postgresql/postgresql_installation.txt +++ b/lib/teamcity/postgresql/postgresql_installation.txt @@ -1,7 +1,7 @@ Installation steps for PostgreSQL for NH TeamCity: -1. Download PostgreSQL (postgresql-9.0.3-1-windows_x64.exe): http://www.enterprisedb.com/products-services-training/pgdownload#windows; +1. Download PostgreSQL: https://www.enterprisedb.com/downloads/postgres-postgresql-downloads; 2. Run the installer ... when prompted to make a password for the service account, make it 'password'; 3. Leave the port number at the default (5432), and leave the default locale; 4. The setup should install PostgreSQL on the machine; @@ -12,8 +12,8 @@ Installation steps for PostgreSQL for NH TeamCity: Creating the NH user: -a. Open pgAdmin III (start -> programs -> PostgreSQL 9.0 -> pgAdmin III); -b. right-click the PostgreSQL 9.0 database, select connect, and enter the password from step 2 above; -c. right-clilck the Login Roles, and select "New Login Role ..."; -d. create a login with "Role name=nhibernate", "Password=nhibernate", and select Superuser on the Role privileges tab. +a. Open pgAdmin 4; +b. Right-click the PostgreSQL database, select connect, and enter the password from step 2 above; +c. Right-clilck the Login Roles, and select "New Login Role ..."; +d. Create a login with "Role name=nhibernate", "Password=nhibernate", and select Superuser on the Role privileges tab. diff --git a/psake.ps1 b/psake.ps1 index 34fa3e2ea37..0eb342b2875 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -29,6 +29,8 @@ Task Set-Configuration { 'connection.connection_string' = 'Server=(local)\SQL2017;Uid=sa;Pwd=Password12!;Database=nhibernateOdbc;Driver={SQL Server Native Client 11.0};Mars_Connection=yes;'; 'connection.driver_class' = 'NHibernate.Driver.OdbcDriver'; 'odbc.explicit_datetime_scale' = '3'; + 'transaction.ignore_session_synchronization_failures' = 'true'; + 'transaction.system_completion_lock_timeout' = '200'; <# We need to use a dialect that avoids mapping DbType.Time to TIME on MSSQL. On modern SQL Server this becomes TIME(7). Later, such values cannot be read back over ODBC. The error we get is "System.ArgumentException : Unknown SQL type - SS_TIME_EX.". I don't know for certain @@ -63,9 +65,22 @@ Task Set-Configuration { }; 'SqlServer2008' = @{ 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;' + 'connection.driver_class' = 'NHibernate.Driver.Sql2008ClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2008Dialect' }; 'SqlServer2012' = @{ 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;'; + 'connection.driver_class' = 'NHibernate.Driver.Sql2008ClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2012Dialect' + }; + 'SqlServer2008-MicrosoftDataSqlClientDriver' = @{ + 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;' + 'connection.driver_class' = 'NHibernate.Driver.MicrosoftDataSqlClientDriver'; + 'dialect' = 'NHibernate.Dialect.MsSql2008Dialect' + }; + 'SqlServer2012-MicrosoftDataSqlClientDriver' = @{ + 'connection.connection_string' = 'Server=(local)\SQL2017;User ID=sa;Password=Password12!;initial catalog=nhibernate;'; + 'connection.driver_class' = 'NHibernate.Driver.MicrosoftDataSqlClientDriver'; 'dialect' = 'NHibernate.Dialect.MsSql2012Dialect' }; 'Oracle' = @{ @@ -117,7 +132,7 @@ Task Test -depends Build { 'NHibernate.Test', 'NHibernate.Test.VisualBasic' ) | ForEach-Object { - $assembly = [IO.Path]::Combine("src", $_, "bin", "Release", "net6.0", "$_.dll") + $assembly = [IO.Path]::Combine("src", $_, "bin", "Release", "net8.0", "$_.dll") Exec { dotnet $assembly --labels=before --nocolor "--result=$_-TestResult.xml" } diff --git a/releasenotes.txt b/releasenotes.txt index 420c05ea2ff..024a2a306d5 100644 --- a/releasenotes.txt +++ b/releasenotes.txt @@ -1,9 +1,284 @@ -Build 5.4.1 +Build 5.5.2 +============================= + +Release notes - NHibernate - Version 5.5.2 + +3 issues were resolved in this release, including CVE CVE-2024-39677 through the merge of 5.4.9. + +** Bug + + * #3536 MemberwiseClone should be virtual error in dotnet 9 preview 3 + +** Task + + * #3578 Release 5.5.1 + * #3577 Merge 5.4.9 into 5.5.x + + +Build 5.5.1 +============================= + +Release notes - NHibernate - Version 5.5.1 + +3 issues were resolved in this release. + +** Bug + + * #3465 Invalid SQL created for some joins in a subquery + +** Task + + * #3509 Release 5.5.1 + * #3508 Merge 5.4.8 into 5.5.x + + +Build 5.5.0 +============================= + +Release notes - NHibernate - Version 5.5.0 + + ##### Possible Breaking Changes ##### + * `Object.Finalize` is no more proxified when the entity base class has a destructor. See #3205. + * Default not-found behavior now works correctly on many-to-many Criteria fetch. It now throws + ObjectNotFoundException exception for not found records. See #2687. + +62 issues were resolved in this release. + +** Bug + + * #3413 Downgrade dependency System.Data.SQLite.Core 1.0.118 -> 1.0.117 + * #3406 Fix orphan removal for detached one-to-one + * #3392 Partial fix fetching lazy property after Select in Linq + * #3360 Incorrect parameter length for char types in MicrosoftDataSqlClientDriver + * #3334 Exception executing HQL query with uncorrelated left joins in subselect + * #3327 HqlParser does not correctly negate EXISTS-nodes below an AND/OR + * #3325 Cascading orphan delete may not work on versioned entity + * #3311 NamedQuery ignores and any other + * #3264 Fix collection filter on subclass columns + * #3256 Invalid SQL is generated for string Enum used in conditional LINQ + * #3205 `Object.Finalize` should not be proxiable + * #2687 Use table group joins for many-to-many in Criteria and Entity loaders + * #1267 NH-3047 - Lazy=no-proxy ignores join fetch + +** New Feature + + * #3242 Linq: add enum Equals and object Equals support + * #3165 Add support for Firebird 4 + * #829 NH-3365 - Support for HasFlag method for enums with Flags attribute applied + +** Improvement + + * #3429 Explicit how to use advanced Redis strategies + * #3410 Remove redundant collection BeforeAssemble call from query cache + * #3398 Do not store mapping field in Configuration + * #3396 Get rid of select queries for each ManyToMany not found ignored element in Criteria and lazy loading + * #3395 Remove ConstantConverter + * #3394 Get rid of select queries for each ManyToMany not found ignored element in hql + * #3390 Enable Not node handling in HqlParser.NegateNode + * #3384 Improve path rule handling with reserved words in Hql.g + * #3377 Move HqlToken.PossibleId to HqlParser.IsPossibleId method and remove castings + * #3374 Simplify aggregateDistinctAll rule in Hql.g + * #3373 Refactor sequential select related members in AbstractEntityPersister + * #3341 Apply fromFragment processing only when required in ProcessDynamicFilterParameters + * #3340 SqlString.Trim should return the same instance for not modified string + * #3253 Do not throw for unknown type in hql case node + * #3230 Add cached boxed boolean values to BooleanType + * #3209 Allow custom query loader + +** Task + + * #3460 Merge 5.4.7 in master + * #3445 Release 5.5.0 + * #3440 Update NUnit to v3.14.0 + * #3423 Update actions/checkout action to v4 + * #3420 Merge 5.4.6 in master + * #3411 Remove ISessionFactoryImplementor parameter from TableGroupJoinHelper + * #3409 Merge 5.4.5 in master + * #3387 Merge 5.4.4 in master + * #3379 Remove NHibernate.Example.Web project + * #3362 Update dependency NUnit3TestAdapter to v4.5.0 + * #3361 Update dependency NUnit.Console to v3.16.3 + * #3353 Migrate renovate config + * #3351 Merge 5.4.3 in master + * #3284 Update NHibernate.Caches to v5.9.0 + * #3283 Update dependency NSubstitute to v5 + * #3280 Add tests for Microsoft.Data.SqlClient driver + * #3275 Migrate dev packages to Cloudsmith + * #3241 Exclude generated files from Deepsource analisys + * #3236 Add MySQL8Dialect and MySQL8InnoDBDialect + * #3223 Simplify GitHub Actions Tests DB initialization + * #3206 Update actions/setup-dotnet action to v3 + * #3202 Update dependency Npgsql to v7 + * #3129 [Security] Update Oracle.ManagedDataAccess + * #3122 Update dependency FirebirdSql.Data.FirebirdClient to v9 + * #3102 Update dependency Microsoft.Data.SqlClient to v3.1.3 + * #3099 [Security] Update dependency System.Linq.Dynamic.Core to v1.3.3 + * #3098 Update dependency System.Data.SQLite.Core to v1.0.118 + * #3092 Update dependency Microsoft.AspNetCore.OData to v7.7.0 + * #3088 Update NUnit to v3.13.3 + +** Tests + + * #3412 Revive hql ParsingFixture + + +Build 5.4.9 +============================= + +Release notes - NHibernate - Version 5.4.9 + +6 issues were resolved in this release, including CVE-2024-39677. + +** Bug + + * #3547 Handle SQL injection vulnerabilities within ObjectToSQLString + +** Task + + * #3576 Release 5.4.9 + * #3558 Migrate AppVeyor & TC builds to PostgreSQL 13 + * #3545 Upgrade Npgsql to a non vulnerable version + * #3544 Upgrade vulnerable test dependencies + * #3517 Obsolete vulnerable literal AddColumn + + +Build 5.4.8 +============================= + +Release notes - NHibernate - Version 5.4.8 + +2 issues were resolved in this release. + +** Bug + + * #3489 Inserting multiple associations of the same entity fails + +** Task + + * #3507 Release 5.4.8 + + +Build 5.4.7 +============================= + +Release notes - NHibernate - Version 5.4.7 + +3 issues were resolved in this release. + +** Task + + * #3459 Release 5.4.7 + * #3458 Merge 5.3.20 into 5.4.x + * #3453 Migrate appveyor build to MySql 8 + + +Build 5.4.6 +============================= + +Release notes - NHibernate - Version 5.4.6 + +2 issues were resolved in this release. + +** Bug + + * #3414 Reenable use of SelectClauseVisitor for subqueries + +** Task + + * #3419 Release 5.4.6 + + +Build 5.4.5 +============================= + +Release notes - NHibernate - Version 5.4.5 + +2 issues were resolved in this release. + +** Task + + * #3408 Release 5.4.5 + * #3407 Merge 5.3.19 in 5.4.x + + +Build 5.4.4 +============================= + +Release notes - NHibernate - Version 5.4.4 + +6 issues were resolved in this release. + +** Bug + + * #3359 2nd level cache GetMany ineffective for collections + * #3354 Invalid program generated by FieldInterceptorProxyBuilder for indexer property getter + * #3352 Fetch throws "could not resolve property" error for a property that is not mapped + +** Improvement + + * #3368 Allow internal entity classes/interfaces in .NET Standard 2.0 for field interceptor + +** Task + + * #3386 Release 5.4.4 + * #3367 Update readme with actual dev build information for 5.4 + + +Build 5.4.3 +============================= + +Release notes - NHibernate - Version 5.4.3 + +11 issues were resolved in this release. + +** Bug + + * #3317 Issue with components list lazy loading with not lazy association + * #3307 IsDirty performance hit since 5.4.0 + * #3295 C# 8/11 Static interface members support + * #3291 Npgsql 6+ issues with null DateTime parameter types + * #3290 Incorrect fetch of Many-to-Many relation + * #3289 Fetching lazy loaded component causes n + 1 query when querying a subclass abstraction + * #3288 NullReferenceException is thrown when using Fetch + +** Task + + * #3349 Release 5.4.3 + * #3348 Merge 5.3.18 in 5.4.x + * #3318 Merge 5.3.17 in 5.4.x + * #3302 Upgrade NUnit3TestAdapter to fix "Unknown framework version 7.0" + + +Build 5.4.2 +============================= + +Release notes - NHibernate - Version 5.4.2 + +6 issues were resolved in this release. + +** Bug + + * #3274 Improve LINQ Contains subquery parameter detection + * #3271 LINQ subqueries wrongly altered by SelectClauseVisitor + * #3263 Wrong alias in Where clause if using Fetch and scalar Select + * #3239 Incorrect SQL generated fetching many-to-many with subclasses + +** New Feature + + * #3251 MappingByCode: Support backfield property access + +** Task + + * #3281 Merge 5.3.16 in 5.4.x + * #3277 Release 5.4.2 + + +Build 5.4.1 ============================= Release notes - NHibernate - Version 5.4.1 -4 issues were resolved in this release. +5 issues were resolved in this release. ** Bug @@ -14,6 +289,7 @@ Release notes - NHibernate - Version 5.4.1 ** Task * #3232 Release 5.4.1 + * #3227 Merge 5.3.15 in 5.4.x As part of releasing 5.4.1, a missing 5.4.0 possible breaking change has been added, about one-to-one associations and optimistic locking. See 5.4.0 possible breaking changes. @@ -209,6 +485,91 @@ Release notes - NHibernate - Version 5.4.0 * #2242 Test case for NH-3972 - SQL error when selecting a column of a subclass when sibling classes have a column of the same name +Build 5.3.20 +============================= + +Release notes - NHibernate - Version 5.3.20 + +2 issues were resolved in this release. + +** Bug + + * #3438 DB2/400: ArgumentException Column 'SQL_TYPE_NAME' does not belong to table DataTypes + +** Task + + * #3454 Release 5.3.20 + + +Build 5.3.19 +============================= + +Release notes - NHibernate - Version 5.3.19 + +2 issues were resolved in this release. + +** Bug + + * #3397 GenerateSchemaCreationScript creates many identical dialect instances + +** Task + + * #3405 Release 5.3.19 + + +Build 5.3.18 +============================= + +Release notes - NHibernate - Version 5.3.18 + +3 issues were resolved in this release. + +** Bug + + * #3333 Lazy property with nosetter accessor remains uninitialized + * #3330 Linq with FetchLazyProperties() resets lazy property changes + +** Task + + * #3346 Release 5.3.18 + + +Build 5.3.17 +============================= + +Release notes - NHibernate - Version 5.3.17 + +5 issues were resolved in this release. + +** Bug + + * #3306 Invalid SQL when referencing nullable entity in correlated subquery + * #3304 Fix SetSnapShot CopyTo variance failure + * #3294 Undefined join type failure with cross joins and Informix + +** Task + + * #3315 Release 5.3.17 + * #3300 Backport handling of null DateTime parameters in Npgsql 6+ + + +Build 5.3.16 +============================= + +Release notes - NHibernate - Version 5.3.16 + +3 issues were resolved in this release. + +** Bug + + * #3269 "Or" clause in a "where" condition returns a wrong result with not-found-ignore + * #3210 Wrong name value for L2 read-only cache warning on mutable + +** Task + + * #3276 Release 5.3.16 + + Build 5.3.15 ============================= diff --git a/src/AsyncGenerator.yml b/src/AsyncGenerator.yml index 1f763ac1df9..9c5f0a43404 100644 --- a/src/AsyncGenerator.yml +++ b/src/AsyncGenerator.yml @@ -187,7 +187,7 @@ scanForMissingAsyncMembers: - all: true - filePath: NHibernate.Test/NHibernate.Test.csproj - targetFramework: net6.0 + targetFramework: net8.0 concurrentRun: true applyChanges: true suppressDiagnosticFailures: diff --git a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml index 9512fef12d6..01395c22e25 100644 --- a/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml +++ b/src/NHibernate.Config.Templates/SapSQLAnywhere.cfg.xml @@ -15,7 +15,9 @@ for your own use before compiling tests in Visual Studio. UID=DBA;PWD=sql;Server=localhost;DBN=nhibernate;DBF=c:\nhibernate.db;ASTOP=No;Enlist=false; - NHibernate.Dialect.SybaseSQLAnywhere12Dialect + NHibernate.Dialect.SapSQLAnywhere17Dialect true=1;false=0 + true + 200 diff --git a/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs b/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs index 748697b6eec..0a6f9fc1f17 100644 --- a/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs +++ b/src/NHibernate.DomainModel/NHSpecific/NullableTypesType.cs @@ -30,11 +30,6 @@ public override object NullSafeGet(DbDataReader rs, string name, ISessionImpleme } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return ReturnedClass.Name; } diff --git a/src/NHibernate.Everything.sln b/src/NHibernate.Everything.sln index c2c257360fc..4d1b272a260 100644 --- a/src/NHibernate.Everything.sln +++ b/src/NHibernate.Everything.sln @@ -70,93 +70,54 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.Tool.HbmXsd", "N EndProject Project("{778DAE3C-4631-46EA-AA77-85C1314464D9}") = "NHibernate.Test.VisualBasic", "NHibernate.Test.VisualBasic\NHibernate.Test.VisualBasic.vbproj", "{7C2EF610-BCA0-4D1F-898A-DE9908E4970C}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.Example.Web", "NHibernate.Example.Web\NHibernate.Example.Web.csproj", "{B291C1C1-599B-418E-8591-8A8CF1CAA188}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHibernate.TestDatabaseSetup", "NHibernate.TestDatabaseSetup\NHibernate.TestDatabaseSetup.csproj", "{783DB85E-2EED-4377-8EF4-8D6EFE042007}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|.NET = Debug|.NET Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms Release|.NET = Release|.NET Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|.NET.ActiveCfg = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|.NET.ActiveCfg = Release|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Any CPU.ActiveCfg = Release|Any CPU {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Any CPU.Build.0 = Release|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {5909BFE7-93CF-4E5F-BE22-6293368AF01D}.Release|Mixed Platforms.Build.0 = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|.NET.ActiveCfg = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Any CPU.Build.0 = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|.NET.ActiveCfg = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Any CPU.ActiveCfg = Release|Any CPU {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Any CPU.Build.0 = Release|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU - {5C649B55-1B3F-4C38-9998-1B043E94A244}.Release|Mixed Platforms.Build.0 = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|.NET.ActiveCfg = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|.NET.ActiveCfg = Release|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Any CPU.ActiveCfg = Release|Any CPU {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Any CPU.Build.0 = Release|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7AEE5B37-C552-4E59-9B6F-88755BCB5070}.Release|Mixed Platforms.Build.0 = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|.NET.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|.NET.ActiveCfg = Release|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Any CPU.ActiveCfg = Release|Any CPU {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Any CPU.Build.0 = Release|Any CPU - {446E148D-A9D5-4D7D-A706-BEDD45B2BC7D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|.NET.ActiveCfg = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|.NET.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.ActiveCfg = Release|Any CPU {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Any CPU.Build.0 = Release|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {7C2EF610-BCA0-4D1F-898A-DE9908E4970C}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|.NET.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|.NET.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|.NET.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|.NET.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Any CPU.Build.0 = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {B291C1C1-599B-418E-8591-8A8CF1CAA188}.Release|Mixed Platforms.Build.0 = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|.NET.ActiveCfg = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|.NET.Build.0 = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Any CPU.Build.0 = Debug|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|.NET.ActiveCfg = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|.NET.Build.0 = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Any CPU.ActiveCfg = Release|Any CPU {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Any CPU.Build.0 = Release|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {783DB85E-2EED-4377-8EF4-8D6EFE042007}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs b/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs deleted file mode 100644 index 38265648eda..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/AppSessionFactory.cs +++ /dev/null @@ -1,40 +0,0 @@ -using NHibernate.Cfg; -using NHibernate.Dialect; -using NHibernate.Driver; -using NHibernate.Example.Web.Models; -using NHibernate.Mapping.ByCode; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class AppSessionFactory - { - public Configuration Configuration { get; } - public ISessionFactory SessionFactory { get; } - - public AppSessionFactory(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) - { - NHibernate.NHibernateLogger.SetLoggersFactory(new NHibernateToMicrosoftLoggerFactory(loggerFactory)); - - var mapper = new ModelMapper(); - mapper.AddMapping(); - var domainMapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); - - Configuration = new Configuration(); - Configuration.DataBaseIntegration(db => - { - db.ConnectionString = @"Server=(local)\SQLEXPRESS;initial catalog=nhibernate;Integrated Security=true"; - db.Dialect(); - db.Driver(); - }) - .AddMapping(domainMapping); - Configuration.SessionFactory().GenerateStatistics(); - - SessionFactory = Configuration.BuildSessionFactory(); - } - - public ISession OpenSession() - { - return SessionFactory.OpenSession(); - } - } -} diff --git a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs b/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs deleted file mode 100644 index a30f2f1236f..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLogger.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; -using System.Collections.Generic; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Logging.Internal; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class NHibernateToMicrosoftLogger : INHibernateLogger - { - private readonly ILogger _msLogger; - - public NHibernateToMicrosoftLogger(ILogger msLogger) - { - _msLogger = msLogger ?? throw new ArgumentNullException(nameof(msLogger)); - } - - private static readonly Dictionary MapLevels = new Dictionary - { - { NHibernateLogLevel.Trace, LogLevel.Trace }, - { NHibernateLogLevel.Debug, LogLevel.Debug }, - { NHibernateLogLevel.Info, LogLevel.Information }, - { NHibernateLogLevel.Warn, LogLevel.Warning }, - { NHibernateLogLevel.Error, LogLevel.Error }, - { NHibernateLogLevel.Fatal, LogLevel.Critical }, - { NHibernateLogLevel.None, LogLevel.None }, - }; - - public void Log(NHibernateLogLevel logLevel, NHibernateLogValues state, Exception exception) - { - _msLogger.Log(MapLevels[logLevel], 0, new FormattedLogValues(state.Format, state.Args), exception, MessageFormatter); - } - - public bool IsEnabled(NHibernateLogLevel logLevel) - { - return _msLogger.IsEnabled(MapLevels[logLevel]); - } - - private static string MessageFormatter(object state, Exception error) - { - return state.ToString(); - } - } -} diff --git a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs b/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs deleted file mode 100644 index 0e732127cd4..00000000000 --- a/src/NHibernate.Example.Web/Infrastructure/NHibernateToMicrosoftLoggerFactory.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System; - -namespace NHibernate.Example.Web.Infrastructure -{ - public class NHibernateToMicrosoftLoggerFactory : INHibernateLoggerFactory - { - private readonly Microsoft.Extensions.Logging.ILoggerFactory _loggerFactory; - - public NHibernateToMicrosoftLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory)); - } - - public INHibernateLogger LoggerFor(string keyName) - { - var msLogger = _loggerFactory.CreateLogger(keyName); - return new NHibernateToMicrosoftLogger(msLogger); - } - - public INHibernateLogger LoggerFor(System.Type type) - { - return LoggerFor( - Microsoft.Extensions.Logging.Abstractions.Internal.TypeNameHelper.GetTypeDisplayName(type)); - } - } -} diff --git a/src/NHibernate.Example.Web/Models/Item.cs b/src/NHibernate.Example.Web/Models/Item.cs deleted file mode 100644 index 7306ed585ca..00000000000 --- a/src/NHibernate.Example.Web/Models/Item.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace NHibernate.Example.Web.Models -{ - public class Item - { - public virtual int Id { get; set; } - public virtual decimal Price { get; set; } - public virtual string Description { get; set; } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Models/ItemMap.cs b/src/NHibernate.Example.Web/Models/ItemMap.cs deleted file mode 100644 index 6f206b8a5ef..00000000000 --- a/src/NHibernate.Example.Web/Models/ItemMap.cs +++ /dev/null @@ -1,16 +0,0 @@ -using NHibernate.Mapping.ByCode; -using NHibernate.Mapping.ByCode.Conformist; - -namespace NHibernate.Example.Web.Models -{ - public class ItemMap : ClassMapping - { - public ItemMap() - { - Lazy(false); - Id(x => x.Id, map => map.Generator(Generators.Native)); - Property(x => x.Price); - Property(x => x.Description); - } - } -} diff --git a/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj b/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj deleted file mode 100644 index 7bd7b9f7109..00000000000 --- a/src/NHibernate.Example.Web/NHibernate.Example.Web.csproj +++ /dev/null @@ -1,35 +0,0 @@ - - - - netcoreapp2.0;net48 - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/NHibernate.Example.Web/Pages/Error.cshtml b/src/NHibernate.Example.Web/Pages/Error.cshtml deleted file mode 100644 index b1f3143a42e..00000000000 --- a/src/NHibernate.Example.Web/Pages/Error.cshtml +++ /dev/null @@ -1,23 +0,0 @@ -@page -@model ErrorModel -@{ - ViewData["Title"] = "Error"; -} - -

Error.

-

An error occurred while processing your request.

- -@if (Model.ShowRequestId) -{ -

- Request ID: @Model.RequestId -

-} - -

Development Mode

-

- Swapping to Development environment will display more detailed information about the error that occurred. -

-

- Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. -

diff --git a/src/NHibernate.Example.Web/Pages/Error.cshtml.cs b/src/NHibernate.Example.Web/Pages/Error.cshtml.cs deleted file mode 100644 index 8c9952f597a..00000000000 --- a/src/NHibernate.Example.Web/Pages/Error.cshtml.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace NHibernate.Example.Web.Pages -{ - public class ErrorModel : PageModel - { - public string RequestId { get; set; } - - public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); - - public void OnGet() - { - RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/Index.cshtml b/src/NHibernate.Example.Web/Pages/Index.cshtml deleted file mode 100644 index d76c879b19c..00000000000 --- a/src/NHibernate.Example.Web/Pages/Index.cshtml +++ /dev/null @@ -1,9 +0,0 @@ -@page -@model IndexModel -@{ - ViewData["Title"] = "NHibernate Demo"; -} - -

NHibernate Demo

-Schema Operations -View Data diff --git a/src/NHibernate.Example.Web/Pages/Index.cshtml.cs b/src/NHibernate.Example.Web/Pages/Index.cshtml.cs deleted file mode 100644 index 9d41b89fca1..00000000000 --- a/src/NHibernate.Example.Web/Pages/Index.cshtml.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; - -namespace NHibernate.Example.Web.Pages -{ - public class IndexModel : PageModel - { - public void OnGet() - { - } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml b/src/NHibernate.Example.Web/Pages/InsertItem.cshtml deleted file mode 100644 index 1f2f61953be..00000000000 --- a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml +++ /dev/null @@ -1,19 +0,0 @@ -@page -@model InsertItemModel -@{ - ViewData["Title"] = "Insert New Item"; -} -
- - - - - - - - - - - -
Price:
Description:
-
\ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs b/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs deleted file mode 100644 index c670497996e..00000000000 --- a/src/NHibernate.Example.Web/Pages/InsertItem.cshtml.cs +++ /dev/null @@ -1,63 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Models; - -namespace NHibernate.Example.Web.Pages -{ - public class InsertItemModel : PageModel - { - [BindProperty] - public InsertItemEvent NewItem { get; set; } - - private readonly ISession _session; - - public InsertItemModel(ISession session) - { - _session = session; - } - - public void OnGet() - { - } - - public IActionResult OnPost() - { - if (!ModelState.IsValid) - { - return Page(); - } - - using (var tx = _session.BeginTransaction()) - { - var item = new Item - { - Price = NewItem.Price, - Description = NewItem.Description, - }; - _session.Save(item); - - tx.Commit(); - } - - return RedirectToPage("/ViewData"); - } - - public IActionResult OnPostCancel() - { - return RedirectToPage("/ViewData"); - } - - public class InsertItemEvent - { - [Required, Range(0.0, double.MaxValue)] - public decimal Price { get; set; } - - public string Description { get; set; } - } - } -} \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/Schema.cshtml b/src/NHibernate.Example.Web/Pages/Schema.cshtml deleted file mode 100644 index ea9f23481b9..00000000000 --- a/src/NHibernate.Example.Web/Pages/Schema.cshtml +++ /dev/null @@ -1,16 +0,0 @@ -@page -@model SchemaModel -@{ - ViewData["Title"] = "Schema Operations"; -} - -Back to the main page - -
-
- - -
-
- -

@Model.Status

\ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs b/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs deleted file mode 100644 index 42b2533fb0e..00000000000 --- a/src/NHibernate.Example.Web/Pages/Schema.cshtml.cs +++ /dev/null @@ -1,68 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Infrastructure; -using NHibernate.Example.Web.Models; -using NHibernate.Tool.hbm2ddl; - -namespace NHibernate.Example.Web.Pages -{ - public class SchemaModel : PageModel - { - [TempData] - public string Status { get; set; } - - private readonly AppSessionFactory _applicationSession; - private readonly ISession _session; - - public SchemaModel(ISession session, AppSessionFactory applicationSession) - { - _applicationSession = applicationSession; - _session = session ?? throw new ArgumentNullException(nameof(session)); - } - - public void OnGet() - { - } - - public IActionResult OnPostCreateSchema() - { - var export = new SchemaExport(_applicationSession.Configuration); - export.Create(false, true); - - using (var tx = _session.BeginTransaction()) - { - var item1 = new Item - { - Description = "First item", - Price = 100m - }; - _session.Save(item1); - - var item2 = new Item - { - Description = "Second item", - Price = 150m - }; - _session.Save(item2); - - tx.Commit(); - } - - Status = "Schema created"; - return RedirectToPage(); - } - - public IActionResult OnPostDropSchema() - { - SchemaExport export = new SchemaExport(_applicationSession.Configuration); - export.Drop(false, true); - - Status = "Schema dropped"; - return RedirectToPage(); - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/ViewData.cshtml b/src/NHibernate.Example.Web/Pages/ViewData.cshtml deleted file mode 100644 index ca4681624aa..00000000000 --- a/src/NHibernate.Example.Web/Pages/ViewData.cshtml +++ /dev/null @@ -1,40 +0,0 @@ -@page -@model ViewDataModel -@{ - ViewData["Title"] = "View Items"; -} - -
- - - - - - @foreach (var item in Model.Items) - { - - @if (Model.Editing == item.Id) - { - - - - - } - else - { - - - - - } - - } -
Item List
IdPriceDescription
- - - @item.Id - - - @item.Id@item.Price@item.Description
-
-Add New Item \ No newline at end of file diff --git a/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs b/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs deleted file mode 100644 index 6ac9785df97..00000000000 --- a/src/NHibernate.Example.Web/Pages/ViewData.cshtml.cs +++ /dev/null @@ -1,90 +0,0 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.RazorPages; -using NHibernate.Example.Web.Models; - -namespace NHibernate.Example.Web.Pages -{ - public class ViewDataModel : PageModel - { - public IList Items { get; set; } - public int? Editing { get; set; } - - private readonly ISession _session; - - public ViewDataModel(ISession session) - { - _session = session; - } - - public void OnGet(int? editing) - { - Editing = editing; - - using (var tx = _session.BeginTransaction()) - { - Items = _session.QueryOver().List(); - } - } - - public IActionResult OnPostEdit(int id) - { - return RedirectToPage(new {editing = id}); - } - - public IActionResult OnPostDelete(int id) - { - using (var tx = _session.BeginTransaction()) - { - var item = _session.Get(id); - if (item != null) - { - _session.Delete(item); - } - - tx.Commit(); - } - - return RedirectToPage(); - } - - public IActionResult OnPostUpdate(int id, UpdateItemEvent updateItem) - { - if (!ModelState.IsValid) - { - return Page(); - } - - using (var tx = _session.BeginTransaction()) - { - var item = _session.Get(id); - if (item != null) - { - item.Price = updateItem.Price; - item.Description = updateItem.Description; - _session.Update(item); - } - - tx.Commit(); - } - - return RedirectToPage(); - } - - public IActionResult OnPostCancelUpdate() - { - return RedirectToPage(); - } - - public class UpdateItemEvent - { - [Required, Range(0.0, double.MaxValue)] - public decimal Price { get; set; } - public string Description { get; set; } - } - } -} diff --git a/src/NHibernate.Example.Web/Pages/_Layout.cshtml b/src/NHibernate.Example.Web/Pages/_Layout.cshtml deleted file mode 100644 index 7db516fb7d5..00000000000 --- a/src/NHibernate.Example.Web/Pages/_Layout.cshtml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - @ViewData["Title"] - - - - @RenderBody() - -

- @Microsoft.Extensions.PlatformAbstractions.PlatformServices.Default.Application.RuntimeFramework -

- -@RenderSection("Scripts", required: false) - - diff --git a/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml b/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml deleted file mode 100644 index 935fef42347..00000000000 --- a/src/NHibernate.Example.Web/Pages/_ViewImports.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@using NHibernate.Example.Web -@namespace NHibernate.Example.Web.Pages -@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers diff --git a/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml b/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml deleted file mode 100644 index a5f10045db9..00000000000 --- a/src/NHibernate.Example.Web/Pages/_ViewStart.cshtml +++ /dev/null @@ -1,3 +0,0 @@ -@{ - Layout = "_Layout"; -} diff --git a/src/NHibernate.Example.Web/Program.cs b/src/NHibernate.Example.Web/Program.cs deleted file mode 100644 index bf57dbb80fe..00000000000 --- a/src/NHibernate.Example.Web/Program.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Serilog; -using Serilog.Events; - -namespace NHibernate.Example.Web -{ - public class Program - { - public static void Main(string[] args) - { - Log.Logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .MinimumLevel.Override("Microsoft", LogEventLevel.Information) - .Enrich.FromLogContext() - .WriteTo.Console() - .CreateLogger(); - - BuildWebHost(args).Run(); - } - - public static IWebHost BuildWebHost(string[] args) => - WebHost.CreateDefaultBuilder(args) - .UseStartup() - .UseSerilog() - .Build(); - } -} diff --git a/src/NHibernate.Example.Web/Properties/launchSettings.json b/src/NHibernate.Example.Web/Properties/launchSettings.json deleted file mode 100644 index a39df606d36..00000000000 --- a/src/NHibernate.Example.Web/Properties/launchSettings.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "iisSettings": { - "windowsAuthentication": false, - "anonymousAuthentication": true, - "iisExpress": { - "applicationUrl": "http://localhost:60203/", - "sslPort": 0 - } - }, - "profiles": { - "IIS Express": { - "commandName": "IISExpress", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - } - }, - "NHibernate.Example.Web": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "http://localhost:60204/" - } - } -} diff --git a/src/NHibernate.Example.Web/Startup.cs b/src/NHibernate.Example.Web/Startup.cs deleted file mode 100644 index 8d21a5e684d..00000000000 --- a/src/NHibernate.Example.Web/Startup.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using NHibernate.Example.Web.Infrastructure; - -namespace NHibernate.Example.Web -{ - public class Startup - { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - public void ConfigureServices(IServiceCollection services) - { - services.AddSingleton(); - services.AddScoped(x => x.GetService().OpenSession()); - - services.AddMvc(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IHostingEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - } - - app.UseStaticFiles(); - - app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller}/{action=Index}/{id?}"); - }); - } - } -} diff --git a/src/NHibernate.Example.Web/appsettings.Development.json b/src/NHibernate.Example.Web/appsettings.Development.json deleted file mode 100644 index fa8ce71a97a..00000000000 --- a/src/NHibernate.Example.Web/appsettings.Development.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } - } -} diff --git a/src/NHibernate.Example.Web/appsettings.json b/src/NHibernate.Example.Web/appsettings.json deleted file mode 100644 index 5fff67bacc4..00000000000 --- a/src/NHibernate.Example.Web/appsettings.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "Logging": { - "IncludeScopes": false, - "LogLevel": { - "Default": "Warning" - } - } -} diff --git a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj index ee40ac1072f..5ea684f06b2 100644 --- a/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj +++ b/src/NHibernate.Test.VisualBasic/NHibernate.Test.VisualBasic.vbproj @@ -8,14 +8,14 @@ On On - + Exe false - + @@ -27,11 +27,11 @@ - - + + - - + + diff --git a/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs b/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs index 4dd0de91f8e..2bc13bba995 100644 --- a/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs +++ b/src/NHibernate.Test/Async/BulkManipulation/HQLBulkOperations.cs @@ -43,5 +43,21 @@ public async Task SimpleDeleteAsync() await (tx.CommitAsync()); } } + + [Test] + public async Task InsertFromSelectWithMultipleAssociationsAsync() + { + Assume.That(TestDialect.NativeGeneratorSupportsBulkInsertion, + "The dialect does not support a native generator compatible with bulk insertion."); + + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + + await (s.CreateQuery("insert into Enrolment (Course, Student)" + + " select e.Course, e.Student from Enrolment e") + .ExecuteUpdateAsync()); + + await (tx.CommitAsync()); + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs index 4e75d4e63b6..9d451fa6da6 100644 --- a/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs +++ b/src/NHibernate.Test/Async/BulkManipulation/NativeSQLBulkOperationsWithCache.cs @@ -33,9 +33,9 @@ public class NativeSQLBulkOperationsWithCacheAsync : TestCase protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); } [Test] diff --git a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs index c3c2195688a..94ebca5e031 100644 --- a/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/BatchableCacheFixture.cs @@ -1565,8 +1565,79 @@ public async Task QueryFetchEntityBatchCacheTestAsync(bool clearEntityCacheAfter Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count"); } + [Test] + public async Task CollectionLazyInitializationFromCacheIsBatchedAsync() + { + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(await (s.Query().Select(x => x.Id).FirstAsync()))); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(await (s.Query().Select(x => x.Id).FirstAsync()))); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + + [Test] + public async Task CollectionLazyInitializationFromCacheIsBatched_FillCacheByQueryCacheAsync() + { + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + int id; + using (var s = OpenSession()) + { + id = await (s.Query().Select(x => x.Id).FirstAsync()); + var readOnly = (await (s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToListAsync())) + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + using (var s = OpenSession()) + { + var readOnly = (await (s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToListAsync())) + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + + + using (var s = OpenSession()) + { + var readOnly = await (s.GetAsync(id)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private async Task AssertMultipleCacheCallsAsync(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, - int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken)) + int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null, CancellationToken cancellationToken = default(CancellationToken)) where TEntity : CacheEntity { var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName); diff --git a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs index f2683f7f26c..27a470f9d9b 100644 --- a/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs +++ b/src/NHibernate.Test/Async/CacheTest/SerializationFixture.cs @@ -30,6 +30,7 @@ namespace NHibernate.Test.CacheTest { using System.Threading.Tasks; + using System.Threading; [TestFixture] public class SerializationFixtureAsync { @@ -312,11 +313,11 @@ private void CheckObjectTypeCacheEntry(AnyType.ObjectTypeCacheEntry original, An Assert.That(copy.EntityName, Is.EqualTo(original.EntityName)); } - private static async Task TestDataContractSerializerAsync(T obj) + private static async Task TestDataContractSerializerAsync(T obj, CancellationToken cancellationToken = default(CancellationToken)) { - var xml = await (DataContractSerializerToXmlAsync(obj)); + var xml = await (DataContractSerializerToXmlAsync(obj, cancellationToken)); obj = DataContractSerializerFromXml(xml); - Assert.That(xml, Is.EqualTo(await (DataContractSerializerToXmlAsync(obj)))); + Assert.That(xml, Is.EqualTo(await (DataContractSerializerToXmlAsync(obj, cancellationToken)))); return obj; } @@ -328,7 +329,7 @@ private static T TestBinaryFormatter(T obj) return obj; } - private static async Task DataContractSerializerToXmlAsync(T obj) + private static async Task DataContractSerializerToXmlAsync(T obj, CancellationToken cancellationToken = default(CancellationToken)) { using (var memoryStream = new MemoryStream()) using (var reader = new StreamReader(memoryStream)) @@ -336,7 +337,7 @@ private static async Task DataContractSerializerToXmlAsync(T obj) var serializer = new DataContractSerializer(typeof(T), KnownTypes); serializer.WriteObject(memoryStream, obj); memoryStream.Position = 0; - return await (reader.ReadToEndAsync()); + return await (reader.ReadToEndAsync(cancellationToken)); } } diff --git a/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs b/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs index 7d7a4a491d1..70134f8b0c8 100644 --- a/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs +++ b/src/NHibernate.Test/Async/Cascade/Circle/MultiPathCircleCascadeTest.cs @@ -54,7 +54,6 @@ protected override string[] Mappings protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs b/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs index c2a78d82e16..647e0cb39d8 100644 --- a/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs +++ b/src/NHibernate.Test/Async/CompositeId/CompositeIdFixture.cs @@ -199,8 +199,8 @@ public async Task MultipleCollectionFetchAsync() Assert.AreEqual(2, c.Orders.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[0]).LineItems)); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[1]).LineItems)); - Assert.AreEqual(((Order) c.Orders[0]).LineItems.Count, 2); - Assert.AreEqual(((Order) c.Orders[1]).LineItems.Count, 2); + Assert.AreEqual(2, ((Order) c.Orders[0]).LineItems.Count); + Assert.AreEqual(2, ((Order) c.Orders[1]).LineItems.Count); await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs b/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs index a0171cba778..55db59272b1 100644 --- a/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs +++ b/src/NHibernate.Test/Async/ConnectionTest/AggressiveReleaseTest.cs @@ -24,13 +24,12 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class AggressiveReleaseTestAsync : ConnectionManagementTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.ReleaseConnections, "after_transaction"); - //cfg.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); - //cfg.SetProperty(Environment.GenerateStatistics, "true"); - cfg.SetProperty(Environment.BatchSize, "0"); + configuration.SetProperty(Environment.ReleaseConnections, "after_transaction"); + //configuration.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); + //configuration.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.BatchSize, "0"); } protected override ISession GetSessionUnderTest() diff --git a/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs b/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs index 1145ecfe31c..18b0dc994b7 100644 --- a/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs +++ b/src/NHibernate.Test/Async/ConnectionTest/BatcherFixture.cs @@ -22,10 +22,9 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class BatcherFixtureAsync : ConnectionManagementTestCase { - protected override void Configure(Configuration config) + protected override void Configure(Configuration configuration) { - base.Configure(config); - config.SetProperty(Environment.BatchSize, "10"); + configuration.SetProperty(Environment.BatchSize, "10"); } protected override ISession GetSessionUnderTest() @@ -53,4 +52,4 @@ public async Task CanCloseCommandsAndUseBatcherAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs index ef2bbf8dae0..8801c0e79c5 100644 --- a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs @@ -3093,7 +3093,7 @@ public async Task CanSetLockModeOnDetachedCriteriaAsync() var countExec = CriteriaTransformer.TransformToRowCount(ec); var countRes = await (countExec.UniqueResultAsync()); - Assert.AreEqual(countRes, 1); + Assert.AreEqual(1, countRes); } } } diff --git a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs index df178490384..c9a7f52a39c 100644 --- a/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Async/Criteria/Lambda/IntegrationFixture.cs @@ -358,7 +358,7 @@ public async Task MultiCriteriaAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); await (SetupPagingDataAsync()); diff --git a/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs b/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs index aca0e5d3660..5c4e82bc1fc 100644 --- a/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs +++ b/src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs @@ -91,7 +91,7 @@ public async Task UsingSqlFunctions_Concat_WithCastAsync() { if(Dialect is Oracle8iDialect) { - Assert.Ignore("Not supported by the active dialect:{0}.", Dialect); + Assert.Ignore($"Not supported by the active dialect:{Dialect}."); } if (TestDialect.HasBrokenTypeInferenceOnSelectedParameters) Assert.Ignore("Current dialect does not support this test"); diff --git a/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs b/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs index b3f6e51b233..405750c3993 100644 --- a/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs +++ b/src/NHibernate.Test/Async/Criteria/ReadonlyTests/QueryOverCacheableTests.cs @@ -27,7 +27,6 @@ protected override void Configure(Configuration config) { config.SetProperty(Environment.UseQueryCache, "true"); config.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(config); } [Test] diff --git a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs index b06fde747f1..072a983f142 100644 --- a/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Async/Criteria/SelectModeTest/SelectModeTest.cs @@ -347,7 +347,7 @@ public async Task SelectModeFetchLazyPropertiesForEntityJoinAsync() Assert.That(NHibernateUtil.IsInitialized(rootChild), Is.True); Assert.That(NHibernateUtil.IsInitialized(parentJoin), Is.True); - Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.Not.Null.Or.Empty); + Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.True); Assert.That(parentJoin.LazyProp, Is.Not.Null.Or.Empty); Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected"); @@ -663,7 +663,7 @@ public async Task FetchModeEagerForEagerAsync() private void SkipFutureTestIfNotSupported() { if (Sfi.ConnectionProvider.Driver.SupportsMultipleQueries == false) - Assert.Ignore("Driver {0} does not support multi-queries", Sfi.ConnectionProvider.Driver.GetType().FullName); + Assert.Ignore($"Driver {Sfi.ConnectionProvider.Driver.GetType().FullName} does not support multi-queries"); } #region Test Setup diff --git a/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs b/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs index 79ed1ab2d69..23fc0eaf206 100644 --- a/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs +++ b/src/NHibernate.Test/Async/EntityModeTest/Map/Basic/DynamicClassFixture.cs @@ -8,12 +8,12 @@ //------------------------------------------------------------------------------ +using System; using System.Collections; using System.Collections.Generic; using System.Dynamic; using System.Linq.Dynamic.Core; using System.Linq; -using Antlr.Runtime.Misc; using NUnit.Framework; using NHibernate.Criterion; using NHibernate.Linq; diff --git a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs index 86b59bbe491..dac7fb16092 100644 --- a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs +++ b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs @@ -74,9 +74,9 @@ public async Task QueryTestWithStrongTypeReturnValueAsync() .Add(Projections.Min("Pay"))); c.SetResultTransformer(trans); ProjectionReport report = await (c.UniqueResultAsync()); - Assert.AreEqual(report.AvgPay, 2.5); - Assert.AreEqual(report.MaxPay, 4); - Assert.AreEqual(report.MinPay, 1); + Assert.AreEqual(2.5, report.AvgPay); + Assert.AreEqual(4, report.MaxPay); + Assert.AreEqual(1, report.MinPay); } } @@ -97,10 +97,10 @@ public async Task QueryTest1Async() Assert.IsTrue(result[0] is object[], "expected object[] as result, but found " + result[0].GetType().Name); object[] results = (object[])result[0]; - Assert.AreEqual(results.Length, 3); - Assert.AreEqual(results[0], 2.5); - Assert.AreEqual(results[1], 4); - Assert.AreEqual(results[2], 1); + Assert.AreEqual(3, results.Length); + Assert.AreEqual(2.5, results[0]); + Assert.AreEqual(4, results[1]); + Assert.AreEqual(1, results[2]); } } @@ -119,7 +119,7 @@ public async Task SelectSqlProjectionTestAsync() IList result = await (c.ListAsync()); // c.UniqueResult(); Assert.IsTrue(result.Count == 1); object results = result[0]; - Assert.AreEqual(results, 2.5); + Assert.AreEqual(2.5, results); } } } diff --git a/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs b/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs index 351cb7daa3c..113983227d3 100644 --- a/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs +++ b/src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs @@ -114,7 +114,7 @@ public async Task ListAddAsync(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after checking existence of non-flushed"); @@ -322,7 +322,7 @@ public async Task ListInsertAsync(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after existence check"); @@ -636,7 +636,7 @@ public async Task ListGetSetAsync(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), "Comparing added company at index {0}", i); + Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), $"Comparing added company at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after adding comparing"); @@ -676,7 +676,7 @@ public async Task ListGetSetAsync(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company ListIndex at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after comparing"); @@ -798,7 +798,7 @@ public async Task ListFlushAsync(bool initialize) { for (var i = 15; i < 20; i++) { - Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, "Removing transient company at index {0}", i); + Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, $"Removing transient company at index {i}"); } Assert.That(FindAllOccurrences(sqlLog.GetWholeLog(), "INSERT \n INTO"), Is.EqualTo(10), "Statements count after removing"); @@ -909,7 +909,7 @@ public async Task ListFlushAsync(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), $"Comparing company ListIndex at index {i}"); } if (initialize) @@ -1049,7 +1049,7 @@ public async Task ListClearAsync(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Credit cards count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, "Checking existence for item at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence for item at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Credit cards initialization status after loading again"); @@ -1140,7 +1140,7 @@ public async Task ListIndexOperationsAsync(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company index at {0}", i); + Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company index at {i}"); } if (initialize) @@ -1882,8 +1882,7 @@ public async Task SetClearAsync(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Permissions count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, - "Checking existence of added element at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence of added element at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Permissions initialization status after loading again"); diff --git a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs index 2783bfead0d..aeb9eb71a9d 100644 --- a/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -44,7 +44,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; } @@ -186,6 +185,18 @@ public async Task TestLinqFetchPropertyAsync() AssertFetchProperty(person); } + [Test] + public async Task TestLinqFetchPropertyAfterSelectAsync() + { + using var s = OpenSession(); + var owner = await (s.Query() + .Select(a => a.Owner) + .Fetch(o => o.Image) + .FirstOrDefaultAsync(o => o.Id == 1)); + + AssertFetchProperty(owner); + } + private static void AssertFetchProperty(Person person) { Assert.That(person, Is.Not.Null); @@ -276,6 +287,45 @@ public async Task TestLinqFetchAllPropertiesAsync() AssertFetchAllProperties(person); } + [TestCase(true)] + [TestCase(false)] + public async Task TestLinqFetchAllProperties_WhenLazyPropertyChangedAsync(bool initLazyPropertyFetchGroup) + { + Person person; + using (var s = OpenSession()) + { + person = await (s.GetAsync(1)); + if (initLazyPropertyFetchGroup) + CollectionAssert.AreEqual(new byte[] { 0 }, person.Image); + + person.Image = new byte[] { 1, 2, 3 }; + + var allPersons = await (s.Query().FetchLazyProperties().ToListAsync()); + // After execute FetchLazyProperties(), I expected to see that the person.Image would be { 1, 2, 3 }. + // Because I changed this person.Image manually, I didn't want to lose those changes. + // But test failed. Оld value returned { 0 }. + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image); + } + } + + [TestCase(true)] + [TestCase(false)] + public async Task TestLinqFetchProperty_WhenLazyPropertyChangedAsync(bool initLazyPropertyFetchGroup) + { + Person person; + using (var s = OpenSession()) + { + person = await (s.GetAsync(1)); + if (initLazyPropertyFetchGroup) + CollectionAssert.AreEqual(new byte[] { 0 }, person.Image); + + person.Image = new byte[] { 1, 2, 3 }; + + var allPersons = await (s.Query().Fetch(x => x.Image).ToListAsync()); + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image); + } + } + private static void AssertFetchAllProperties(Person person) { Assert.That(person, Is.Not.Null); diff --git a/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs b/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs index 2b4a25c95a0..f0418657911 100644 --- a/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs +++ b/src/NHibernate.Test/Async/FilterTest/DynamicFilterTest.cs @@ -108,7 +108,7 @@ public async Task CombinedClassAndCollectionFiltersEnabledAsync() salespersons = await (session.CreateQuery("select s from Salesperson as s left join fetch s.Orders").ListAsync()); Assert.AreEqual(1, salespersons.Count, "Incorrect salesperson count"); sp = (Salesperson) salespersons[0]; - Assert.AreEqual(sp.Orders.Count, 1, "Incorrect order count"); + Assert.AreEqual(1, sp.Orders.Count, "Incorrect order count"); } } diff --git a/src/NHibernate.Test/Async/Futures/FallbackFixture.cs b/src/NHibernate.Test/Async/Futures/FallbackFixture.cs index 52f091d60b9..68e2c8603da 100644 --- a/src/NHibernate.Test/Async/Futures/FallbackFixture.cs +++ b/src/NHibernate.Test/Async/Futures/FallbackFixture.cs @@ -43,8 +43,7 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + using (var cp = ConnectionProviderFactory.NewConnectionProvider(configuration.Properties)) { if (cp.Driver is SqlClientDriver) { diff --git a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 9756052f341..ea6dada5ab7 100644 --- a/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Async/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -36,7 +36,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs index 12ab309a529..281ed163c32 100644 --- a/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/Async/GhostProperty/GhostPropertyFixture.cs @@ -253,5 +253,54 @@ public async Task WillFetchJoinInSingleHqlQueryAsync() Assert.DoesNotThrow(() => { var x = order.Payment; }); } + + [Test(Description = "GH-1267(NH-3047)")] + public async Task WillFetchJoinInAdditionalHqlQueryAsync() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + order = (await (s.CreateQuery("from Order o where o.Id = 1").ListAsync()))[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + // ... then join-fetch the related payment + await (s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").ListAsync()); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } + + [Test(Description = "GH-1267(NH-3047)")] + public async Task WillFetchJoinWithCriteriaAsync() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + + var query = s.CreateCriteria(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = (await (query.ListAsync()))[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + query2.Add(Criterion.Restrictions.Eq("Id", 1)); + query2.Fetch(SelectMode.Fetch, "Payment"); + await (query2.ListAsync()); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } } } diff --git a/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs b/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs index dbd820ee55f..b6a3f3c2bea 100644 --- a/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs +++ b/src/NHibernate.Test/Async/Hql/Ast/BulkManipulation.cs @@ -884,7 +884,7 @@ public async Task SimpleDeleteOnAnimalAsync() { if (Dialect.HasSelfReferentialForeignKeyBug) { - Assert.Ignore("self referential FK bug", "HQL delete testing"); + Assert.Ignore("self referential FK bug - HQL delete testing"); return; } diff --git a/src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs b/src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs index d185faef1e0..e1c6011fcf2 100644 --- a/src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs +++ b/src/NHibernate.Test/Async/Hql/EntityJoinHqlTest.cs @@ -358,6 +358,15 @@ from x2 in session.Query() //GH-2988 var withNullOrValidList = await (session.Query().Where(x => x.ManyToOne.Id == validManyToOne.Id || x.ManyToOne == null).ToListAsync()); var withNullOrValidList2 = await (session.Query().Where(x => x.ManyToOne == null || x.ManyToOne.Id == validManyToOne.Id).ToListAsync()); + //GH-3269 + var invalidId = Guid.NewGuid(); + var withInvalidOrValid = await (session.Query().Where(x => x.OneToOne.Id == invalidId || x.ManyToOne.Id == validManyToOne.Id).ToListAsync()); + var withInvalidOrNull = await (session.Query().Where(x => x.ManyToOne.Id == invalidId || x.OneToOne == null).ToListAsync()); + var withInvalidOrNotNull = await (session.Query().Where(x => x.ManyToOne.Id == invalidId || x.OneToOne != null).ToListAsync()); + + Assert.That(withInvalidOrValid.Count, Is.EqualTo(1)); + Assert.That(withInvalidOrNull.Count, Is.EqualTo(2)); + Assert.That(withInvalidOrNotNull.Count, Is.EqualTo(0)); //GH-3185 var mixImplicitAndLeftJoinList = await (session.Query().Where(x => x.ManyToOne.Id == validManyToOne.Id && x.OneToOne == null).ToListAsync()); diff --git a/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs b/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs index af898bcf8e6..62636575ef6 100644 --- a/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs +++ b/src/NHibernate.Test/Async/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs @@ -43,7 +43,7 @@ public async Task ReturnedValueIsGuidAsync() } catch (NotSupportedException) { - Assert.Ignore("This test does not apply to {0}", Dialect.Dialect.GetDialect()); + Assert.Ignore($"This test does not apply to {Dialect.Dialect.GetDialect()}"); } var gen = new NativeGuidGenerator(); diff --git a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index a5e9222fd42..2432a8705c1 100644 --- a/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Async/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -496,7 +496,7 @@ public async Task CreateWithNonEmptyManyToManyCollectionMergeWithNewElementAsync s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs b/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs index b75063bd44e..dec48eda73f 100644 --- a/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs +++ b/src/NHibernate.Test/Async/Immutable/ImmutableTest.cs @@ -29,7 +29,6 @@ public class ImmutableTestAsync : TestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs b/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs index 009ba2ba2d7..5f5a7f2fc15 100644 --- a/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs +++ b/src/NHibernate.Test/Async/LazyGroup/LazyGroupFixture.cs @@ -30,7 +30,6 @@ public class LazyGroupFixtureAsync : TestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs b/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs index e7714c07a49..78ff4a50a16 100644 --- a/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs +++ b/src/NHibernate.Test/Async/LazyProperty/LazyPropertyFixture.cs @@ -13,10 +13,10 @@ using System.Linq; using NHibernate.Cfg; using NHibernate.Intercept; +using NHibernate.Linq; using NHibernate.Tuple.Entity; using NUnit.Framework; using NUnit.Framework.Constraints; -using NHibernate.Linq; namespace NHibernate.Test.LazyProperty { @@ -67,6 +67,7 @@ protected override void OnSetUp() Id = 1, ALotOfText = "a lot of text ...", Image = new byte[10], + NoSetterImage = new byte[10], FieldInterceptor = "Why not that name?" }); tx.Commit(); @@ -229,6 +230,9 @@ public async Task CanGetValueForNonLazyPropertyAsync() Assert.That(book.Name, Is.EqualTo("some name")); Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?")); Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False); + //GH-3354 Exception accessing indexer property + Assert.That(book[0], Is.EqualTo(0)); + Assert.DoesNotThrow(() => book[0] = 0); } } @@ -391,5 +395,58 @@ public async Task CanMergeTransientWithLazyPropertyInCollectionAsync() Assert.That(book.Words.First().Content, Is.EqualTo(new byte[1] { 0 })); } } + + [Test(Description = "GH-3333")] + public async Task GetLazyPropertyWithNoSetterAccessor_PropertyShouldBeInitializedAsync() + { + using (ISession s = OpenSession()) + { + var book = await (s.GetAsync(1)); + var image = book.NoSetterImage; + // Fails. Property remains uninitialized after it has been accessed. + Assert.That(NHibernateUtil.IsPropertyInitialized(book, "NoSetterImage"), Is.True); + } + } + + [Test(Description = "GH-3333")] + public async Task GetLazyPropertyWithNoSetterAccessorTwice_ResultsAreSameObjectAsync() + { + using (ISession s = OpenSession()) + { + var book = await (s.GetAsync(1)); + var image = book.NoSetterImage; + var sameImage = book.NoSetterImage; + // Fails. Each call to a property getter returns a new object. + Assert.That(ReferenceEquals(image, sameImage), Is.True); + } + } + + [Test] + public async Task CanSetValueForLazyPropertyNoSetterAsync() + { + Book book; + using (ISession s = OpenSession()) + { + book = await (s.GetAsync(1)); + book.NoSetterImage = new byte[]{10}; + } + + Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True); + CollectionAssert.AreEqual(book.NoSetterImage, new byte[] { 10 }); + } + + [Test] + public async Task CanFetchLazyPropertyNoSetterAsync() + { + using (ISession s = OpenSession()) + { + var book = await (s + .Query() + .Fetch(x => x.NoSetterImage) + .FirstAsync(x => x.Id == 1)); + + Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True); + } + } } } diff --git a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs index f7f7f1a2b8f..0254b826f9a 100644 --- a/src/NHibernate.Test/Async/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Async/Legacy/FooBarTest.cs @@ -16,6 +16,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; @@ -1078,8 +1079,8 @@ public async Task PropertyRefAsync() using (ISession s = OpenSession()) { Holder h = (Holder) await (s.LoadAsync(typeof(Holder), hid)); - Assert.AreEqual(h.Name, "foo"); - Assert.AreEqual(h.OtherHolder.Name, "bar"); + Assert.AreEqual("foo", h.Name); + Assert.AreEqual("bar", h.OtherHolder.Name); object[] res = (object[]) (await (s.CreateQuery("from Holder h join h.OtherHolder oh where h.OtherHolder.Name = 'bar'").ListAsync()))[0]; Assert.AreSame(h, res[0]); @@ -1222,10 +1223,7 @@ public async Task BatchLoadAsync() await (s.DeleteAsync(baz2)); await (s.DeleteAsync(baz3)); - IEnumerable en = new JoinedEnumerable( - new IEnumerable[] {baz.FooSet, baz2.FooSet}); - - foreach (object obj in en) + foreach (var obj in baz.FooSet.Concat(baz2.FooSet)) { await (s.DeleteAsync(obj)); } @@ -1430,7 +1428,7 @@ public async Task SortablesAsync() // DictionaryEntry key - not the index. foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } @@ -1446,7 +1444,7 @@ public async Task SortablesAsync() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } await (s.FlushAsync()); @@ -1461,7 +1459,7 @@ public async Task SortablesAsync() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } await (s.DeleteAsync(b)); @@ -5273,16 +5271,13 @@ public async Task TransientOrphanDeleteAsync() Baz baz = new Baz(); var bars = new HashSet { new Bar(), new Bar(), new Bar() }; baz.CascadingBars = bars; - IList foos = new List(); - foos.Add(new Foo()); - foos.Add(new Foo()); + var foos = new List { new Foo(), new Foo() }; baz.FooBag = foos; await (s.SaveAsync(baz)); - IEnumerator enumer = new JoinedEnumerable(new IEnumerable[] {foos, bars}).GetEnumerator(); - while (enumer.MoveNext()) + foreach (var foo in foos.Concat(bars.Cast())) { - FooComponent cmp = ((Foo) enumer.Current).Component; + var cmp = foo.Component; await (s.DeleteAsync(cmp.Glarch)); cmp.Glarch = null; } diff --git a/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs b/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs index 97d7277918f..d96bd6deacb 100644 --- a/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs +++ b/src/NHibernate.Test/Async/Legacy/MasterDetailTest.cs @@ -184,7 +184,7 @@ public async Task CopyCascadeAsync() // Save parent and cascade update detached child Category persistentParent = await (s.MergeAsync(parent)); Assert.IsTrue(persistentParent.Subcategories.Count == 1); - Assert.AreEqual(((Category) persistentParent.Subcategories[0]).Name, "child2"); + Assert.AreEqual("child2", ((Category) persistentParent.Subcategories[0]).Name); await (s.FlushAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs b/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs index 3d9119be986..9e539f3e7fd 100644 --- a/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs +++ b/src/NHibernate.Test/Async/Legacy/SQLLoaderTest.cs @@ -481,7 +481,7 @@ public async Task ComponentNoStarAsync() IQuery q = session.CreateSQLQuery(sql).AddEntity("comp", typeof(Componentizable)); IList list = await (q.ListAsync(cancellationToken)); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); Componentizable co = (Componentizable) list[0]; diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs index 14e4fdf91ef..e71660b4b1d 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/AverageTests.cs @@ -25,7 +25,7 @@ public async Task CanGetAverageOfIntegersAsDoubleAsync() //NH-2429 var average = await (db.Products.AverageAsync(x => x.UnitsOnOrder)); - Assert.AreEqual(average, 10.129870d, 0.000001d); + Assert.AreEqual(10.129870d, average, 0.000001d); } } } diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs index c7b618793e4..5a332bb9865 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/GroupByHavingTests.cs @@ -22,7 +22,6 @@ public class GroupByHavingTestsAsync : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs b/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs index 99a234a483a..b40a07f6159 100644 --- a/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs +++ b/src/NHibernate.Test/Async/Linq/ByMethod/OrderByTests.cs @@ -22,7 +22,6 @@ public class OrderByTestsAsync : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/Linq/EnumTests.cs b/src/NHibernate.Test/Async/Linq/EnumTests.cs index c869012844c..2fb552412f5 100644 --- a/src/NHibernate.Test/Async/Linq/EnumTests.cs +++ b/src/NHibernate.Test/Async/Linq/EnumTests.cs @@ -174,13 +174,11 @@ public async Task ConditionalNavigationPropertyAsync() } } - [Test] - public async Task CanQueryComplexExpressionOnTestEnumAsync() + [TestCase(null)] + [TestCase(TestEnum.Unspecified)] + public async Task CanQueryComplexExpressionOnTestEnumAsync(TestEnum? type) { - //TODO: Fix issue on SQLite with type set to TestEnum.Unspecified - TestEnum? type = null; using (var session = OpenSession()) - using (var trans = session.BeginTransaction()) { var entities = session.Query(); @@ -197,7 +195,7 @@ public async Task CanQueryComplexExpressionOnTestEnumAsync() coalesce = user.NullableEnum1 ?? TestEnum.Medium }).ToListAsync()); - Assert.That(query.Count, Is.EqualTo(0)); + Assert.That(query.Count, Is.EqualTo(type == TestEnum.Unspecified ? 1 : 0)); } } diff --git a/src/NHibernate.Test/Async/Linq/FunctionTests.cs b/src/NHibernate.Test/Async/Linq/FunctionTests.cs index e47e3d22c37..2a46df8e1e1 100644 --- a/src/NHibernate.Test/Async/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Async/Linq/FunctionTests.cs @@ -204,7 +204,7 @@ where lowerName.IndexOf('a') == 0 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -220,7 +220,7 @@ where lowerName.IndexOf('a', 2) == -1 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -236,7 +236,7 @@ where lowerName.IndexOf("an") == 0 select lowerName; var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -252,7 +252,7 @@ where lowerName.Contains("a") select lowerName.IndexOf("a", 1); var result = await (query.ToListAsync()); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); await (ObjectDumper.WriteAsync(query)); } @@ -459,6 +459,33 @@ where item.Discount.Equals(-1) await (ObjectDumper.WriteAsync(query)); } + [Test] + public async Task WhereEnumEqualAsync() + { + var query = from item in db.PatientRecords + where item.Gender.Equals(Gender.Female) + select item; + + await (ObjectDumper.WriteAsync(query)); + + query = from item in db.PatientRecords + where item.Gender.Equals(item.Gender) + select item; + + await (ObjectDumper.WriteAsync(query)); + } + + + [Test] + public async Task WhereObjectEqualAsync() + { + var query = from item in db.PatientRecords + where ((object) item.Gender).Equals(Gender.Female) + select item; + + await (ObjectDumper.WriteAsync(query)); + } + [Test] public async Task WhereEquatableEqualAsync() { diff --git a/src/NHibernate.Test/Async/Linq/MethodCallTests.cs b/src/NHibernate.Test/Async/Linq/MethodCallTests.cs index b3ba92bef4f..621aed6d57c 100644 --- a/src/NHibernate.Test/Async/Linq/MethodCallTests.cs +++ b/src/NHibernate.Test/Async/Linq/MethodCallTests.cs @@ -59,6 +59,7 @@ public async Task CanExecuteCountWithOrderByArgumentsAsync() public async Task CanSelectPropertiesIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Name, u.InvalidLoginAttempts}) .FirstAsync()); @@ -71,6 +72,7 @@ public async Task CanSelectPropertiesIntoObjectArrayAsync() public async Task CanSelectComponentsIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Component, u.Component.OtherComponent}) .FirstAsync()); @@ -106,6 +108,7 @@ public async Task CanSelectConstantsIntoObjectArrayAsync() const string name = "Julian"; var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, pi, name, DateTime.MinValue}) .FirstAsync()); @@ -119,6 +122,7 @@ public async Task CanSelectConstantsIntoObjectArrayAsync() public async Task CanSelectPropertiesFromAssociationsIntoObjectArrayAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Role.Name, u.Role.Entity.Output}) .FirstAsync()); @@ -131,6 +135,7 @@ public async Task CanSelectPropertiesFromAssociationsIntoObjectArrayAsync() public async Task CanSelectPropertiesIntoObjectArrayInPropertyAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new object[] { u.Id, u.Name, new object[u.Id] } }) .FirstAsync()); @@ -144,6 +149,7 @@ public async Task CanSelectPropertiesIntoObjectArrayInPropertyAsync() public async Task CanSelectPropertiesIntoPropertyListInPropertyAsync() { var result = await (db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new List { u.Id, u.Name, new object[u.Id] } }) .FirstAsync()); @@ -156,7 +162,7 @@ public async Task CanSelectPropertiesIntoPropertyListInPropertyAsync() [Test, Description("NH-2744")] public async Task CanSelectPropertiesIntoNestedObjectArraysAsync() { - var query = db.Users.Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); + var query = db.Users.OrderBy(u => u.Id).Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); var result = await (query.FirstAsync()); Assert.That(result.Length, Is.EqualTo(2)); diff --git a/src/NHibernate.Test/Async/Linq/PagingTests.cs b/src/NHibernate.Test/Async/Linq/PagingTests.cs index 6c72ddd1f4d..c4ea2530d11 100644 --- a/src/NHibernate.Test/Async/Linq/PagingTests.cs +++ b/src/NHibernate.Test/Async/Linq/PagingTests.cs @@ -136,7 +136,7 @@ public async Task Customers11to20Async() var query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); } @@ -146,19 +146,19 @@ public async Task Customers11to20And21to30ShouldNoCacheQueryAsync() var query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(20).Take(10).ToListAsync()); - Assert.AreNotEqual(query[0], "BSBEV"); + Assert.AreNotEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = await ((from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(20).ToListAsync()); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(20, query.Count); } diff --git a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs index 1f55f7b6cb8..4c16951e8a0 100644 --- a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs @@ -36,8 +36,6 @@ public PreEvaluationTestsAsync(bool legacy, bool fallback) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.FormatSql, "false"); configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, LegacyPreEvaluation.ToString()); configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString()); diff --git a/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs b/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs index 3bc5fb1bedc..f8418a1c113 100644 --- a/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryCacheableTests.cs @@ -21,11 +21,10 @@ namespace NHibernate.Test.Linq [TestFixture] public class QueryCacheableTestsAsync : LinqTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(cfg); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs b/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs index 54216c4642e..66f65c7bfab 100644 --- a/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryFlushModeTests.cs @@ -22,7 +22,6 @@ public class QueryFlushModeTestsAsync : LinqTestCase protected override void Configure(Configuration configuration) { configuration.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs b/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs index d7ae3c3917e..9bf5eaf04bf 100644 --- a/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs +++ b/src/NHibernate.Test/Async/Linq/QueryTimeoutTests.cs @@ -32,7 +32,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchStrategy, typeof(TimeoutCatchingNonBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/Linq/WhereTests.cs b/src/NHibernate.Test/Async/Linq/WhereTests.cs index 56d183e49c9..47809de4738 100644 --- a/src/NHibernate.Test/Async/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Async/Linq/WhereTests.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Linq.Expressions; using log4net.Core; +using NHibernate.Dialect; using NHibernate.Engine.Query; using NHibernate.Linq; using NHibernate.DomainModel.Northwind.Entities; @@ -67,6 +68,32 @@ public async Task WhereWithConstantExpressionAsync() Assert.That(query.Count, Is.EqualTo(1)); } + [Test(Description = "GH-3256")] + public async Task CanUseStringEnumInConditionalAsync() + { + var query = db.Users + .Where( + user => (user.Enum1 == EnumStoredAsString.Small + ? EnumStoredAsString.Small + : EnumStoredAsString.Large) == user.Enum1) + .Select(x => x.Enum1); + + Assert.That(await (query.CountAsync()), Is.GreaterThan(0)); + } + + [Test(Description = "GH-3256")] + public async Task CanUseStringEnumInConditional2Async() + { + var query = db.Users + .Where( + user => (user.Enum1 == EnumStoredAsString.Small + ? user.Enum1 + : EnumStoredAsString.Large) == user.Enum1) + .Select(x => x.Enum1); + + Assert.That(await (query.CountAsync()), Is.GreaterThan(0)); + } + [Test] public async Task FirstElementWithWhereAsync() { @@ -644,6 +671,51 @@ where sheet.Users.Contains(user) Assert.That(query.Count, Is.EqualTo(2)); } + [Test] + public async Task TimesheetsWithEnumerableContainsOnSelectAsync() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var value = (EnumStoredAsInt32) 1000; + var query = await ((from sheet in db.Timesheets + where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) + select sheet).ToListAsync()); + + Assert.That(query.Count, Is.EqualTo(1)); + } + + [Test] + public async Task TimesheetsWithProjectionInSubqueryAsync() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = await ((from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToListAsync()); + + Assert.That(query.Count, Is.EqualTo(2)); + } + + [Test] + public async Task ContainsSubqueryWithCoalesceStringEnumSelectAsync() + { + if (Dialect is MsSqlCeDialect || Dialect is SQLiteDialect) + Assert.Ignore("Dialect is not supported"); + + var results = + await (db.Timesheets.Where( + o => + o.Users + .Where(u => u.Id != 0.MappedAs(NHibernateUtil.Int32)) + .Select(u => u.Name == u.Name ? u.Enum1 : u.NullableEnum1.Value) + .Contains(EnumStoredAsString.Small)) + .ToListAsync()); + + Assert.That(results.Count, Is.EqualTo(1)); + } + [Test] public async Task SearchOnObjectTypeWithExtensionMethodAsync() { diff --git a/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs b/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs index 81f6b14b5cd..1734c5daaab 100644 --- a/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs +++ b/src/NHibernate.Test/Async/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs @@ -44,7 +44,6 @@ protected override void Configure(Configuration configuration) x.MultiTenancyConnectionProvider(); }); configuration.Properties[Cfg.Environment.GenerateStatistics] = "true"; - base.Configure(configuration); } private static void ValidateSqlServerConnectionAppName(ISession s, string tenantId) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs index 9485aff8ae1..f28d3983bc9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs @@ -45,7 +45,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs index ddd35ad0018..b49f3a1dd85 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs @@ -32,7 +32,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.LinqToHqlGeneratorsRegistry(); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs index 99930c1bdb5..bb1db7853e2 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/FileStreamSql2008/Fixture.cs @@ -39,10 +39,10 @@ protected override bool AppliesTo(Dialect.Dialect dialect) return dialect is MsSql2008Dialect; } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { //Points to the database created with FileStream Filegroup. - cfg.Properties["connection.connection_string"] = + configuration.Properties["connection.connection_string"] = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=FileStreamDB;Integrated Security=True;Pooling=False"; #region CREATE DATABASE example diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs index 29c4aabe5cc..40ebdcc36ba 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/Fixture.cs @@ -20,47 +20,45 @@ public class FixtureAsync : BugTestCase { protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity {Name = "Bob"}; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - var e2 = new Entity {Name = "Sally"}; - session.Save(e2); + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - transaction.Commit(); - } + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public async Task YourTestNameAsync() { - using (var session = OpenSession()) - using (session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - } + await (transaction.CommitAsync()); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs index 073d534694a..0e4b4057d80 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH0000/FixtureByCode.cs @@ -21,12 +21,12 @@ namespace NHibernate.Test.NHSpecificTest.GH0000 /// Fixture using 'by code' mappings /// /// - /// This fixture is identical to except the mapping is performed + /// This fixture is identical to except the mapping is performed /// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach /// if you prefer. /// [TestFixture] - public class ByCodeFixtureAsync : TestCaseMappingByCode + public class FixtureByCodeAsync : TestCaseMappingByCode { protected override HbmMapping GetMappings() { @@ -42,48 +42,46 @@ protected override HbmMapping GetMappings() protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity { Name = "Bob" }; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - var e2 = new Entity { Name = "Sally" }; - session.Save(e2); + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); - transaction.Commit(); - } + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHbernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public async Task YourTestNameAsync() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); - await (transaction.CommitAsync()); - } + await (transaction.CommitAsync()); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH0829/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH0829/Fixture.cs new file mode 100644 index 00000000000..36015f3d1c6 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH0829/Fixture.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH0829 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Parent { Type = TestEnum.A | TestEnum.C }; + session.Save(e1); + + var e2 = new Child { Type = TestEnum.D, Parent = e1 }; + session.Save(e2); + + var e3 = new Child { Type = TestEnum.C, Parent = e1 }; + session.Save(e3); + + transaction.Commit(); + } + + [Test] + public async Task SelectClassAsync() + { + using var session = OpenSession(); + + var resultFound = await (session.Query().Where(x => x.Type.HasFlag(TestEnum.A)).FirstOrDefaultAsync()); + + var resultNotFound = await (session.Query().Where(x => x.Type.HasFlag(TestEnum.D)).FirstOrDefaultAsync()); + + Assert.That(resultFound, Is.Not.Null); + Assert.That(resultNotFound, Is.Null); + } + + [Test] + public async Task SelectChildClassContainedInParentAsync() + { + using var session = OpenSession(); + + var result = await (session.Query().Where(x => x.Parent.Type.HasFlag(x.Type)).FirstOrDefaultAsync()); + + Assert.That(result, Is.Not.Null); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + foreach (var entity in new[] { nameof(Child), nameof(Parent) }) + { + session.CreateQuery($"delete from {entity}").ExecuteUpdate(); + } + + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs new file mode 100644 index 00000000000..a95df9e5f21 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1228/Fixture.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1228 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [Test] + public async Task TestThetaJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatWorks.ListAsync()); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatWorks.ListAsync()); + } + + [Test] + public async Task TestAnsiJoinOnAssociationInSubQueryAsync() + { + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + + using var s = OpenSession(); + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + } + + [Test] + public async Task TestOtherAnsiJoinOnAssociationInSubQueryAsync() + { + using var s = OpenSession(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + await (queryThatCreatesWrongSQL.ListAsync()); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + await (queryThatCreatesWrongSQL.ListAsync()); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs new file mode 100644 index 00000000000..1a5d5f38c88 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1313/Fixture.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var account = new Account { Id = 1, Name = "Account_1", OldAccountNumber = 1 }; + var order = new HoldClose + { + Account = account, + CloseDate = new DateTime(2023, 1, 1) + }; + + session.Save(account); + session.Save(order); + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + transaction.Commit(); + } + + [Test] + [Explicit("Not fixed yet")] + public async Task ManyToOneTargettingAFormulaAsync() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session.Query(); + + Assert.That(await (result.ToListAsync()), Has.Count.EqualTo(1)); + await (transaction.CommitAsync()); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs index 69b6e469b6a..89a0d71729c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1486/Fixture.cs @@ -24,7 +24,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(_interceptor); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs index 117d2290eb4..e3e0e0572ee 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1496/Fixture.cs @@ -28,7 +28,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.AppendListeners(ListenerType.PostUpdate, new[] { _auditEventListener }); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs index a9b6818c04f..fc0c9255d40 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1547/Fixture.cs @@ -34,8 +34,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); DriverForSubstitutedCommand.DriverClass = driverClass; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs index 3b9b66878df..dd7a05ab15d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1730/Fixture.cs @@ -19,7 +19,7 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void OnTearDown() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs index 2f2e042fa1d..1245739aa76 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1754/Fixture.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -86,7 +87,7 @@ public async Task CanAddChildAfterFlushAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -104,7 +105,7 @@ public async Task CanAddChildAfterFlushWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -132,7 +133,7 @@ public async Task CanMergeWithTransientChildAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -153,7 +154,7 @@ public async Task CanMergeWithTransientChildWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -179,7 +180,7 @@ public async Task CanChangeOwnershipOnFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -192,7 +193,7 @@ public async Task CanChangeOwnershipOnFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -215,7 +216,7 @@ public async Task CanChangeOwnershipOnFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -228,7 +229,7 @@ public async Task CanChangeOwnershipOnFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -254,7 +255,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -267,7 +268,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -290,7 +291,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -303,7 +304,7 @@ public async Task CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -329,7 +330,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -342,7 +343,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -365,7 +366,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -378,7 +379,7 @@ public async Task CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransact Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -404,7 +405,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -417,7 +418,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -440,7 +441,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -453,7 +454,7 @@ public async Task CanChangeOwnershipOnNonFlushedParentsWithoutTransactionAsync() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs similarity index 83% rename from src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs rename to src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs index ff47bd2ad14..0c930f421f3 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH1994/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs @@ -10,7 +10,6 @@ using System.Linq; using NHibernate.Criterion; -using NHibernate.Dialect; using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; @@ -20,7 +19,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1994 { using System.Threading.Tasks; [TestFixture] - public class FixtureAsync : BugTestCase + public class ManyToManyFilteredFixtureAsync : BugTestCase { protected override void OnSetUp() { @@ -41,14 +40,7 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.Delete("from System.Object"); - transaction.Commit(); } } @@ -70,9 +62,6 @@ public async Task TestUnfilteredLinqQueryAsync() [Test] public async Task TestFilteredByWhereCollectionLinqQueryAsync() { - if(Dialect is PostgreSQLDialect) - Assert.Ignore("Dialect doesn't support 0/1 to bool implicit cast"); - using (var s = OpenSession()) { var query = await (s.Query() @@ -150,5 +139,31 @@ public async Task TestQueryOverRestrictionWithClauseAsync() Assert.That(query[0].Documents.Count, Is.EqualTo(1), "filtered asset documents"); } } + + [Test] + public async Task LazyLoadAsync() + { + using (var s = OpenSession()) + { + var asset = await (s.Query().FirstAsync()); + Assert.That(asset.Documents.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } + + [Test] + public async Task LazyLoadFilteredAsync() + { + using (var s = OpenSession()) + { + s.EnableFilter("deletedFilter").SetParameter("deletedParam", false); + + var asset = await (s.Query().FirstAsync()); + Assert.That(asset.Documents.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs index 89586bfd9fb..1a71937cd19 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs @@ -26,7 +26,6 @@ public CircularReferenceFetchDepth0FixtureAsync() : base(0) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", "0"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs index 5687c0cac44..6365722a0cc 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs @@ -28,7 +28,6 @@ public CircularReferenceFetchDepthFixtureAsync(int depth) : base(depth) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", _depth.ToString()); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs index 13702eb1171..2a140d31b9c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3113/FixtureByCode.cs @@ -44,8 +44,6 @@ protected override void Configure(Configuration configuration) var dialect = NHibernate.Dialect.Dialect.GetDialect(configuration.Properties); if (dialect is Oracle8iDialect) configuration.SetProperty(Environment.Dialect, typeof(Oracle9iDialect).FullName); - - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs index 3694b370c39..c95a70f4286 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3176/FixtureByCode.cs @@ -60,7 +60,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs index a95cbcebfca..76b11bac687 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3198/FixtureByCode.cs @@ -32,7 +32,6 @@ protected override void Configure(Configuration configuration) { new TestEventListener() }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs index 8d5772bf3d5..89ceb740018 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3215/FixtureByCode.cs @@ -45,7 +45,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs new file mode 100644 index 00000000000..9c4a297af9c --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3263 +{ + using System.Threading.Tasks; + [TestFixture] + public class ReuseFetchJoinFixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var em = new Employee() { Name = "x", OptionalInfo = new OptionalInfo() }; + em.OptionalInfo.Employee = em; + s.Save(em); + t.Commit(); + } + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task ReuseJoinScalarSelectAsync() + { + using var session = OpenSession(); + await (session.Query() + .Fetch(x => x.OptionalInfo) + .Where(x => x.OptionalInfo != null) + .Select(x => new { x.OptionalInfo.Age }) + .ToListAsync()); + } + + [Test] + public async Task ReuseJoinScalarSelectHqlAsync() + { + using var session = OpenSession(); + await (session.CreateQuery( + "select x.OptionalInfo.Age " + + "from Employee x " + + "fetch x.OptionalInfo " + + "where x.OptionalInfo != null ").ListAsync()); + + } + + [Test] + public async Task ReuseJoinScalarSelectHql2Async() + { + using var session = OpenSession(); + await (session.CreateQuery( + "select x.OptionalInfo.Age " + + "from Employee x " + + "join fetch x.OptionalInfo o " + + "where o != null ").ListAsync()); + } + + [Test] + public async Task ReuseJoinScalarSelectHql3Async() + { + using var session = OpenSession(); + await (session.CreateQuery( + "select x.OptionalInfo.Age from Employee x " + + "join fetch x.OptionalInfo " + + "where x.OptionalInfo != null ").ListAsync()); + } + + [Test] + public async Task ReuseJoinEntityAndScalarSelectAsync() + { + using var session = OpenSession(); + using var sqlLog = new SqlLogSpy(); + + var x = await (session.Query() + .Fetch(x => x.OptionalInfo) + .Where(x => x.OptionalInfo != null) + .Select(x => new { x, x.OptionalInfo.Age }) + .FirstAsync()); + + Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(x.x.OptionalInfo), Is.True); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs new file mode 100644 index 00000000000..0a1d6d97655 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3288 +{ + using System.Threading.Tasks; + [TestFixture] + public class FetchAndCollectionJoinFixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var middleEntity = new MiddleEntity(); + middleEntity.Components.Add(new Component { MiddleEntity = middleEntity, Value = 1 }); + var te = new TopEntity + { + MiddleEntity = middleEntity + }; + session.Save(middleEntity); + session.Save(te); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Delete("from System.Object"); + + transaction.Commit(); + } + + [Test] + public async Task ReuseEntityJoinWithCollectionJoinAsync() + { + using var session = OpenSession(); + + var entities = await (session.Query() + .Fetch(e => e.MiddleEntity) + .Where(e => e.MiddleEntity.Components.Any(e => e.Value != 0)) + .ToListAsync()); + Assert.That(entities.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3289/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3289/FixtureByCode.cs new file mode 100644 index 00000000000..721d35848ab --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3289/FixtureByCode.cs @@ -0,0 +1,111 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3289 +{ + using System.Threading.Tasks; + [TestFixture] + public class ByCodeFixtureAsync : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Identity)); + rc.Property(x => x.Name); + rc.Component(x => x.Component); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Identity)); + rc.Property(x => x.Name); + rc.Component(x => x.Component); + }); + mapper.JoinedSubclass(rc => + { + rc.Key(k => k.Column("Id")); + rc.Property(x => x.SomeProperty); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.Lazy(true); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new SubEntity { Name = "Jim" }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + if (Dialect.SupportsTemporaryTables) + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + else + session.Delete("from System.Object"); + + transaction.Commit(); + } + + [Test] + public async Task TestSubEntityInterfaceWithFetchIsPropertyInitializedAsync() + { + using var session = OpenSession(); + var data = await (session.Query() + .Fetch(e => e.Component) + .ToListAsync()); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + + [Test] + public async Task TestEntityInterfaceWithFetchIsPropertyInitializedAsync() + { + using var session = OpenSession(); + var data = await (session.Query() + .Fetch(e => e.Component) + .ToListAsync()); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + + [Test] + public async Task TestSubEntityWithFetchIsPropertyInitializedAsync() + { + using var session = OpenSession(); + var data = await (session.Query() + .Fetch(e => e.Component) + .ToListAsync()); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3290/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3290/Fixture.cs new file mode 100644 index 00000000000..77229193cbf --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3290/Fixture.cs @@ -0,0 +1,147 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3290 +{ + using System.Threading.Tasks; + [TestFixture(true)] + [TestFixture(false)] + public class FixtureAsync : TestCaseMappingByCode + { + private readonly bool _detectFetchLoops; + + public FixtureAsync(bool detectFetchLoops) + { + _detectFetchLoops = detectFetchLoops; + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + + rc.Property( + x => x.Name + ); + + rc.Set( + x => x.Children, + v => + { + v.Table("EntityToEntity"); + v.Cascade(Mapping.ByCode.Cascade.None); + v.Inverse(true); + v.Key(x => + { + x.Column("ParentId"); + x.NotNullable(true); + }); + v.Lazy(CollectionLazy.Lazy); + v.Fetch(CollectionFetchMode.Join); + }, + h => h.ManyToMany(m => m.Column("ChildId")) + ); + + rc.Set( + x => x.Parents, + v => + { + v.Table("EntityToEntity"); + v.Cascade(Mapping.ByCode.Cascade.All); + + v.Key(x => + { + x.Column("ChildId"); + x.NotNullable(true); + }); + v.Lazy(CollectionLazy.Lazy); + v.Fetch(CollectionFetchMode.Join); + }, + h => h.ManyToMany(m => m.Column("ParentId")) + ); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.DetectFetchLoops, _detectFetchLoops ? "true" : "false"); + configuration.SetProperty(Environment.MaxFetchDepth, _detectFetchLoops ? "-1" : "2"); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var person = new Entity + { + Name = "pers", + Parents = new HashSet() + }; + session.Save(person); + var job = new Entity + { + Name = "job", + Children = new HashSet() + }; + session.Save(job); + + job.Children.Add(person); + person.Parents.Add(job); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateSQLQuery("delete from EntityToEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task QueryWithFetchAsync() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + var all = await (session + .QueryOver() + .Fetch(SelectMode.Fetch, x => x.Children) + .Fetch(SelectMode.Fetch, x => x.Parents) + .TransformUsing(Transformers.DistinctRootEntity) + .ListAsync()); + + foreach (var entity in all) + { + var isPerson = entity.Name == "pers"; + if (isPerson) + Assert.That(entity.Parents, Has.Count.EqualTo(1), "Person's job not found or non-unique."); + else + Assert.That(entity.Children, Has.Count.EqualTo(1), "Job's employee not found or non-unique."); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3291/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3291/Fixture.cs new file mode 100644 index 00000000000..0d898115b80 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3291/Fixture.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Linq; +using NHibernate.Criterion; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3291 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Person { Name = "Bob", DateOfBirth = new DateTime(2009, 12, 23) }; + session.Save(e1); + + var e2 = new Person { Name = "Sally", DateOfBirth = new DateTime(2018, 9, 30) }; + session.Save(e2); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task LinqAsync() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + DateTime? dateOfSearch = null; + + var result = await (( + from person in session.Query() + where dateOfSearch == null || person.DateOfBirth > dateOfSearch + select person).ToListAsync()); + + Assert.That(result, Has.Count.EqualTo(2)); + } + + [Test] + public async Task HqlAsync() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + DateTime? dateOfSearch = null; + + var result = + await (session.CreateQuery("from Person where :DateOfSearch is null OR DateOfBirth > :DateOfSearch") + .SetParameter("DateOfSearch", dateOfSearch, NHibernateUtil.DateTime) + .ListAsync()); + + Assert.That(result, Has.Count.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs new file mode 100644 index 00000000000..ba446d194f9 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs @@ -0,0 +1,69 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3306NullableEntityCorrelatedSubquery +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + private const string NAME_JOE = "Joe"; + private const string NAME_ALLEN = "Allen"; + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var joe = new Customer { Name = NAME_JOE }; + session.Save(joe); + + var allen = new Customer { Name = NAME_ALLEN }; + session.Save(allen); + + var joeInvoice0 = new Invoice { Customer = joe, Number = 0 }; + session.Save(joeInvoice0); + + var allenInvoice1 = new Invoice { Customer = allen, Number = 1 }; + session.Save(allenInvoice1); + + tx.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + session.Delete("from Invoice"); + session.Delete("from Customer"); + tx.Commit(); + } + } + + [Test] + public async Task NullableEntityInCorrelatedSubqueryAsync() + { + using (var s = OpenSession()) + { + var customers = s.Query().Where(c => c.Name == NAME_JOE); + var results = await (s.Query() + .Where(i => customers.Any(c => c.Invoices.Any(ci => ci.Customer == i.Customer))).ToListAsync()); + + Assert.That(results.Count, Is.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs new file mode 100644 index 00000000000..4ddde3d2a41 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Data; +using NHibernate.Dialect; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + using System.Threading.Tasks; + [TestFixture] + public class SqlQueryParamTypeFixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new Entity {Name = "Bob"}; + session.Save(e1); + + var e2 = new Entity {Name = "Sally"}; + session.Save(e2); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + (Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)) + || Dialect is SQLiteDialect); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task AppliesParameterTypeFromQueryParamAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + await (s.GetNamedQuery("entityIdByName").SetParameter("name", "Bob").UniqueResultAsync()); + Assert.That(log.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs new file mode 100644 index 00000000000..1ca210a186e --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3317/FixtureByCode.cs @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3317 +{ + using System.Threading.Tasks; + [TestFixture(true)] + [TestFixture(false)] + public class ComponentsListFixtureAsync : TestCaseMappingByCode + { + private readonly bool _fetchJoinMapping; + private Guid _id; + + public ComponentsListFixtureAsync(bool fetchJoinMapping) + { + _fetchJoinMapping = fetchJoinMapping; + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var tr = session.BeginTransaction(); + var root = new Entity(); + root.Entries.Add(new ComponentListEntry { ComponentReference = null, DummyString = "one", }); + + session.Save(root); + tr.Commit(); + _id = root.Id; + } + + [Test] + public async Task LazyLoadingAsync() + { + using var newSession = OpenSession(); + var reloadedRoot = await (newSession.GetAsync(_id)); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + [Test] + public async Task QueryOverFetchAsync() + { + using var newSession = OpenSession(); + var reloadedRoot = await (newSession.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Entries) + .Where(x => x.Id == _id) + .SingleOrDefaultAsync()); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + [Test] + public async Task LinqFetchAsync() + { + using var newSession = OpenSession(); + var reloadedRoot = await (newSession.Query() + .Fetch(x => x.Entries) + .Where(x => x.Id == _id) + .SingleOrDefaultAsync()); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateSQLQuery("delete from Entries").ExecuteUpdate(); + session.Delete("from System.Object"); + transaction.Commit(); + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.Property(x => x.Name); + + rc.Bag( + x => x.Entries, + v => + { + if (_fetchJoinMapping) + v.Fetch(CollectionFetchMode.Join); + }, + h => h.Component(cmp => + { + cmp.Property(x => x.DummyString); + cmp.ManyToOne(x => x.ComponentReference); + })); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.ManyToOne(x => x.Parent, m => m.NotNullable(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.Property(x => x.Name); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs new file mode 100644 index 00000000000..da325b51328 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3325/Fixture.cs @@ -0,0 +1,121 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + using System.Threading.Tasks; + using System.Threading; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task CanRemoveChildAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildAfterSaveAndExplicitFlushAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + [Test] + public async Task CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlushAsync() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + await (session.SaveAsync(parent)); + await (session.FlushAsync()); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + await (t.CommitAsync()); + + await (AssertParentIsChildlessAsync(parentId, childId)); + } + + private async Task AssertParentIsChildlessAsync(Guid parentId, Guid childId, CancellationToken cancellationToken = default(CancellationToken)) + { + using var session = OpenSession(); + + var parent = await (session.GetAsync(parentId, cancellationToken)); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = await (session.GetAsync(childId, cancellationToken)); + Assert.That(child, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs new file mode 100644 index 00000000000..dd487c61382 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3327/Fixture.cs @@ -0,0 +1,79 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child", Parent = parent }; + session.Save(parent); + session.Save(child); + t.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task NotIsCorrectlyHandledAsync() + { + using var session = OpenSession(); + var q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That((await (q.ListAsync()))[0], Is.EqualTo(1)); + + q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That((await (q.ListAsync()))[0], Is.EqualTo(0)); + } + + [Test] + public async Task NotNotExistsNegatedAsync() + { + using var log = new SqlLogSpy(); + using var session = OpenSession(); + var results = await (session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + NOT EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND NOT ROOT.Name = 'Parent' + )").ListAsync()); + Assert.That(log.GetWholeLog(), Does.Not.Contains(" NOT ").IgnoreCase); + Assert.That(results.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..b25d10169a7 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,204 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public async Task NoExceptionOnExecuteQueryAsync(TestCaseItem testCase) + { + using var session = OpenSession(); + var q = session.CreateQuery(testCase.Hql); + Assert.That(await (q.ListAsync()), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs new file mode 100644 index 00000000000..07b1a219f83 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs @@ -0,0 +1,174 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + using System.Threading.Tasks; + [TestFixture] + public class FetchFromNotMappedBaseClassFixtureAsync : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name, m => m.Lazy(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.ManyToOne(x => x.Parent, m => m.ForeignKey("none")); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Component(x => x.Component); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.ManyToOne(x => x.Entity, m => m.ForeignKey("none")); + rc.Lazy(true); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var np = new EntityComponentMapped { Component = new Component { Field = "x" } }; + session.Save(np); + var e = new EntityParentMapped { Parent = np }; + session.Save(e); + var nameMapped = new EntityNameMapped { Name = "lazy" }; + session.Save(nameMapped); + np.Component.Entity = nameMapped; + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task CanFetchLazyComponentFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Component).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [Test] + public async Task CanFetchLazyComponentThenEntityFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query() + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanFetchLazyPropertyFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Name).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Name))); + Assert.That(result.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanThenFetchLazyComponentFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Parent).ThenFetch(x => x.Component).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0].Parent; + Assert.That(NHibernateUtil.IsInitialized(result), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [KnownBug("GH-3356")] + [Test(Description = "GH-3356" )] + public async Task FetchAfterSelectAsync() + { + using var log = new SqlLogSpy(); + + using var s = OpenSession(); + var list = await (s.Query() + .Select(x => x.Parent) + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToListAsync()); + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public async Task CanFetchEntityFromNotMappedBaseClassAsync() + { + using var session = OpenSession(); + var list = await (session.Query().Fetch(x => x.Parent).ToListAsync()); + + Assert.That(list, Has.Count.EqualTo(1)); + Assert.That(list[0].Parent, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(list[0].Parent)); + } + + [Test] + public void FetchNotMappedAssociationThrowsAsync() + { + using var session = OpenSession(); + var query = session.Query().Fetch(x => x.Parent); + + Assert.ThrowsAsync(() => query.ToListAsync()); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs new file mode 100644 index 00000000000..85c119e905c --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3403OneToOne/Fixture.cs @@ -0,0 +1,74 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + private Guid _id; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = new Entity1 + { + Child = new Entity2() + }; + + entity.Child.Parent = entity; + + session.Save(entity); + transaction.Commit(); + _id = entity.Id; + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task OrphanDeleteForDetachedOneToOneAsync() + { + Guid childId; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var entity = await (session.GetAsync(_id)); + childId = entity.Child.Id; + await (session.EvictAsync(entity.Child)); + entity.Child = null; + + await (session.FlushAsync()); + await (transaction.CommitAsync()); + } + + using (var session = OpenSession()) + { + var entity = await (session.GetAsync(_id)); + Assert.That(entity, Is.Not.Null); + Assert.That(entity.Child, Is.Null, "Unexpected child on parent"); + + var child = await (session.GetAsync(childId)); + Assert.That(child , Is.Null, "Child is still in database"); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs new file mode 100644 index 00000000000..ed8822a4311 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3421/Fixture.cs @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlCommand; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + using System.Threading.Tasks; + [TestFixture] + public class ByCodeFixtureAsync : TestCaseMappingByCode + { + private SqlInterceptor _interceptor; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Component(x => x.Attributes, new { + Sku = (string)null + }, dc => { + dc.Property(x => x.Sku); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + base.Configure(configuration); + + _interceptor = new SqlInterceptor(); + + configuration.SetInterceptor(_interceptor); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally", Attributes = new Dictionary() { + { "Sku", "AAA" } + } }; + session.Save(e2); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from Entity").ExecuteUpdate(); + transaction.Commit(); + } + } + + [Test] + public async Task TestFlushDoesNotTriggerAnUpdateAsync() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var foo = await (session.Query().ToListAsync()); + + await (session.FlushAsync()); + + var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList(); + + Assert.That(updateStatements, Has.Count.EqualTo(0)); + } + } + + public class SqlInterceptor : EmptyInterceptor + { + public IList SqlStatements = new List(); + + public override SqlString OnPrepareStatement(SqlString sql) + { + SqlStatements.Add(sql); + + return base.OnPrepareStatement(sql); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs new file mode 100644 index 00000000000..ef60ff14aac --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3424/Fixture.cs @@ -0,0 +1,60 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Collections.Generic; +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var c1 = new Child { Name = "Rob" }; + session.Save(c1); + var e1 = new Entity { Name = "Bob", Children = new HashSet { c1 } }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete Child").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public async Task QueryingAfterFutureThenClearAsync() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var futureBob = session.Query().Where(e => e.Name == "Bob").ToFutureValue(q => q.FirstOrDefault()); + var bob = await (futureBob.GetValueAsync()); + Assert.That(bob, Is.Not.Null); + session.Clear(); + + var allQuery = session.Query(); + Assert.That(() => allQuery.ToListAsync(), Has.Count.EqualTo(1)); + await (transaction.CommitAsync()); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs new file mode 100644 index 00000000000..8d4b62bb325 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3465/Fixture.cs @@ -0,0 +1,31 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + [Test] + public void ThetaJoinSubQueryAsync() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var query = session.CreateQuery("select e.Id from EntityA e where exists (from e.Children b, EntityC c)"); + Assert.DoesNotThrowAsync(() => query.ListAsync()); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs new file mode 100644 index 00000000000..63c89db566d --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3474/Fixture.cs @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NUnit.Framework; +using NHibernate.Linq; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 }; + session.Save(e1); + + var e2 = new ChequePayment { Bank = "CA", Amount = 32 }; + session.Save(e2); + + var e3 = new CashPayment { Amount = 18.5m }; + session.Save(e3); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + // Polymorphic updates require support of temp tables. + return Dialect.SupportsTemporaryTables; + } + + [Test] + public async Task PolymorphicUpdateShouldNotCommitAsync() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var payment = await (session.Query().FirstAsync()); + payment.Amount = 100; + await (session.FlushAsync()); + + await (session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdateAsync()); + + await (transaction.RollbackAsync()); + } + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + IPayment payment = await (session.Query().FirstAsync()); + Assert.That(payment.Amount, Is.EqualTo(50m)); + + payment = await (session.Query().FirstAsync()); + Assert.That(payment.Amount, Is.EqualTo(32m)); + + await (transaction.CommitAsync()); + } + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs b/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs new file mode 100644 index 00000000000..f63dcb43745 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/GH3516/FixtureByCode.cs @@ -0,0 +1,399 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NHibernate.Type; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureByCodeAsync : TestCaseMappingByCode + { + + private readonly HashSet _unsupportedProperties = new(); + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.FirstChar); + rc.Property(x => x.CharacterEnum, m => m.Type>()); + rc.Property(x => x.UriProperty); + + rc.Property(x => x.ByteProperty); + rc.Property(x => x.DecimalProperty); + rc.Property(x => x.DoubleProperty); + rc.Property(x => x.FloatProperty); + rc.Property(x => x.ShortProperty); + rc.Property(x => x.IntProperty); + rc.Property(x => x.LongProperty); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.SByte)) + rc.Property(x => x.SByteProperty); + else + _unsupportedProperties.Add(nameof(Entity.SByteProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt16)) + rc.Property(x => x.UShortProperty); + else + _unsupportedProperties.Add(nameof(Entity.UShortProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt32)) + rc.Property(x => x.UIntProperty); + else + _unsupportedProperties.Add(nameof(Entity.UIntProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt64)) + rc.Property(x => x.ULongProperty); + else + _unsupportedProperties.Add(nameof(Entity.ULongProperty)); + + rc.Property(x => x.DateTimeProperty); + rc.Property(x => x.DateProperty, m => m.Type(NHibernateUtil.Date)); + if (TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet)) + rc.Property(x => x.DateTimeOffsetProperty); + else + _unsupportedProperties.Add(nameof(Entity.DateTimeOffsetProperty)); + rc.Property(x => x.TimeProperty, m => m.Type(NHibernateUtil.Time)); + + rc.Property(x => x.GuidProperty); + }); + + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Discriminator(x => x.Column("StringDiscriminator")); + rc.Property(x => x.Name); + rc.Abstract(true); + }); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithSingleQuote)); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithEscapedSingleQuote)); + + mapper.Import(); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private CultureInfo _backupCulture; + private CultureInfo _backupUICulture; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Save( + new Entity + { + Name = Entity.NameWithSingleQuote, + FirstChar = Entity.QuoteInitial, + CharacterEnum = CharEnum.SingleQuote, + UriProperty = Entity.UriWithSingleQuote + }); + session.Save( + new Entity + { + Name = Entity.NameWithEscapedSingleQuote, + FirstChar = Entity.BackslashInitial, + CharacterEnum = CharEnum.Backslash, + UriProperty = Entity.UriWithEscapedSingleQuote + }); + + transaction.Commit(); + + _backupCulture = CultureInfo.CurrentCulture; + _backupUICulture = CultureInfo.CurrentUICulture; + } + + protected override void OnTearDown() + { + if (_backupCulture != null) + { + CultureInfo.CurrentCulture = _backupCulture; + CultureInfo.CurrentUICulture = _backupUICulture; + } + + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + private static readonly string[] StringInjectionsProperties = + { + nameof(Entity.NameWithSingleQuote), nameof(Entity.NameWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(StringInjectionsProperties))] + public void SqlInjectionInStringsAsync(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.Name = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with name {propertyName}"); + } + + private static readonly string[] SpecialNames = + { + "\0; drop table Entity; --", + "\b; drop table Entity; --", + "\n; drop table Entity; --", + "\r; drop table Entity; --", + "\t; drop table Entity; --", + "\x1A; drop table Entity; --", + "\"; drop table Entity; --", + "\\; drop table Entity; --" + }; + + [TestCaseSource(nameof(SpecialNames))] + public async Task StringsWithSpecialCharactersAsync(string name) + { + // We may not even be able to insert the entity. + var wasInserted = false; + try + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var e = new Entity { Name = name }; + await (s.SaveAsync(e)); + await (t.CommitAsync()); + + wasInserted = true; + } + catch (Exception e) + { + Assert.Warn($"The entity insertion failed with message {e}"); + } + + try + { + using var session = OpenSession(); + Entity.ArbitraryStringValue = name; + var list = await (session.CreateQuery($"from Entity e where e.Name = Entity.{nameof(Entity.ArbitraryStringValue)}").ListAsync()); + if (wasInserted && list.Count != 1) + Assert.Warn($"Unable to find entity with name {nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception e) + { + Assert.Warn($"The query has failed with message {e}"); + } + + // Check the db is not wrecked. + if (wasInserted) + { + using var session = OpenSession(); + var list = await (session + .CreateQuery("from Entity e where e.Name = :name") + .SetString("name", name) + .ListAsync()); + Assert.That(list, Has.Count.EqualTo(1)); + } + else + { + using var session = OpenSession(); + var all = await (session.CreateQuery("from Entity e").ListAsync()); + Assert.That(all, Has.Count.GreaterThan(0)); + } + } + + [Test] + public async Task SqlInjectionInStringDiscriminatorAsync() + { + using var session = OpenSession(); + + await (session.SaveAsync(new Subclass1 { Name = "Subclass1" })); + await (session.SaveAsync(new Subclass2 { Name = "Subclass2" })); + + // ObjectToSQLString is used for generating the inserts. + Assert.That(session.Flush, Throws.Nothing, "Unable to flush the subclasses"); + + foreach (var entityName in new[] { nameof(Subclass1), nameof(Subclass2) }) + { + var query = session.CreateQuery($"from {entityName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, $"Unable to list entities of {entityName}"); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find the {entityName} entity"); + } + } + + private static readonly string[] CharInjectionsProperties = + { + nameof(Entity.QuoteInitial), nameof(Entity.BackslashInitial) + }; + + [TestCaseSource(nameof(CharInjectionsProperties))] + public void SqlInjectionInCharAsync(string propertyName) + { + using var session = OpenSession(); + var query = session.CreateQuery($"from Entity e where e.FirstChar = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Is.Not.Null.And.Count.EqualTo(1), $"Unable to find entity with initial {propertyName}"); + } + + private static readonly string[] CharEnumInjections = + { + nameof(CharEnum.SingleQuote), nameof(CharEnum.Backslash) + }; + + [TestCaseSource(nameof(CharEnumInjections))] + public void SqlInjectionWithCharEnumAsync(string enumName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.CharacterEnum = CharEnum.{enumName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with CharacterEnum {enumName}"); + } + + private static readonly string[] UriInjections = + { + nameof(Entity.UriWithSingleQuote), nameof(Entity.UriWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(UriInjections))] + public void SqlInjectionWithUriAsync(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.UriProperty = Entity.{propertyName}"); + IList list = null; + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with UriProperty {propertyName}"); + } + + private static readonly string[] NumericalTypesInjections = + { + nameof(Entity.ByteProperty), + nameof(Entity.DecimalProperty), + nameof(Entity.DoubleProperty), + nameof(Entity.FloatProperty), + nameof(Entity.ShortProperty), + nameof(Entity.IntProperty), + nameof(Entity.LongProperty), + nameof(Entity.SByteProperty), + nameof(Entity.UShortProperty), + nameof(Entity.UIntProperty), + nameof(Entity.ULongProperty) + }; + + [TestCaseSource(nameof(NumericalTypesInjections))] + public async Task SqlInjectionInNumericalTypeAsync(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + Entity.ArbitraryStringValue = "0; drop table Entity; --"; + using (var session = OpenSession()) + { + IQuery query; + // Defining that query is invalid and should throw. + try + { + query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception ex) + { + // All good. + Assert.Pass($"The wicked query creation has been rejected, as it should: {ex}"); + // Needed for the compiler who does not know "Pass" always throw. + return; + } + + // The query definition has been accepted, run it. + try + { + await (query.ListAsync()); + } + catch (Exception ex) + { + // Expecting no exception at that point, but the test is to check if the injection succeeded. + Assert.Warn($"The wicked query execution has failed: {ex}"); + } + } + + // Check if we can still query Entity. If it succeeds, at least it means the injection failed. + using (var session = OpenSession()) + { + IList list = null; + Assert.That(async () => list = await (session.CreateQuery("from Entity e").ListAsync()), Throws.Nothing); + Assert.That(list, Has.Count.GreaterThan(0)); + } + } + + private static readonly string[] DateTypesInjections = + { + nameof(Entity.DateTimeProperty), + nameof(Entity.DateProperty), + nameof(Entity.DateTimeOffsetProperty), + nameof(Entity.TimeProperty) + }; + + [TestCaseSource(nameof(DateTypesInjections))] + public void SqlInjectionWithDatetimeAsync(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + var wickedCulture = new CultureInfo("en-US"); + if (propertyName == nameof(Entity.TimeProperty)) + wickedCulture.DateTimeFormat.ShortTimePattern = "HH:mm:ss\\'\"; drop table Entity; --\""; + else + wickedCulture.DateTimeFormat.ShortDatePattern = "yyyy-MM-ddTHH:mm:ss\\'\"; drop table Entity; --\""; + CultureInfo.CurrentCulture = wickedCulture; + CultureInfo.CurrentUICulture = wickedCulture; + + using var session = OpenSession(); + + var staticPropertyName = propertyName == nameof(Entity.DateTimeOffsetProperty) ? + nameof(Entity.StaticDateTimeOffsetProperty) : nameof(Entity.StaticDateProperty); + var query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{staticPropertyName}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + + private static readonly string[] GuidInjections = + { + Entity.NameWithSingleQuote, Entity.NameWithEscapedSingleQuote + }; + + [TestCaseSource(nameof(GuidInjections))] + public void SqlInjectionWithGuidAsync(string injection) + { + Entity.ArbitraryStringValue = $"{Guid.NewGuid()}{injection}"; + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.GuidProperty = Entity.{nameof(Entity.ArbitraryStringValue)}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(async () => list = await (query.ListAsync()), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs index b528d151b8f..d41df353d6f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Logs/LogsFixture.cs @@ -46,7 +46,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs index 2fe3e8a8894..ec66ea4ef4c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1001/Fixture.cs @@ -21,7 +21,7 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } private int employeeId; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs index 8be29780dca..700e2ed4714 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs @@ -204,7 +204,7 @@ public async Task QueryMapElementsAsync() var a = await (query.UniqueResultAsync()); - Assert.AreEqual(a.C[1], "Text1"); + Assert.AreEqual("Text1", a.C[1]); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs index 83fba185e25..56fecfc34d6 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1101/Fixture.cs @@ -22,8 +22,7 @@ public class FixtureAsync : BugTestCase protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs index b5758daa27f..336968543bc 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1144/Fixture.cs @@ -21,12 +21,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1144 [TestFixture] public class FixtureAsync : BugTestCase { - private Configuration configuration; - protected override void Configure(Configuration configuration) { - this.configuration = configuration; - this.configuration.Properties[Environment.BatchSize] = "10"; + configuration.Properties[Environment.BatchSize] = "10"; } [Test] diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs index 20691ec53ea..aa36b45ef3d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1253/Fixture.cs @@ -85,7 +85,7 @@ public async Task MultiQuerySingleInListAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (var tx = s.BeginTransaction()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs new file mode 100644 index 00000000000..998c03fd985 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1284/Fixture.cs @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH1284 +{ + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void OnTearDown() + { + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + s.Delete("from Person"); + tx.Commit(); + } + + [Test] + public async Task EmptyValueTypeComponentAsync() + { + Person jimmy; + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + var p = new Person("Jimmy Hendrix"); + await (s.SaveAsync(p)); + await (tx.CommitAsync()); + } + + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) + { + jimmy = await (s.GetAsync("Jimmy Hendrix")); + await (tx.CommitAsync()); + } + + Assert.That(jimmy.Address, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs index 641113b1e29..aba848d70a5 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1394/Fixture.cs @@ -105,9 +105,9 @@ public async Task CanOrderBySubqueryProjectionAsync() // Oracle order NULL Last (ASC) nullRelationOffSet = 0; } - Assert.AreEqual(list[nullRelationOffSet].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet + 1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet + 2].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet + 1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet + 2].Name); } } } @@ -133,9 +133,9 @@ public async Task CanOrderBySubqueryProjectionDescAsync() // Oracle order NULL First (DESC) nullRelationOffSet = 2; } - Assert.AreEqual(list[nullRelationOffSet+2].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet+1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet+2].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet+1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet].Name); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs index 22143a7fb7b..e6959c4d31a 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1413/PagingTest.cs @@ -39,7 +39,7 @@ public async Task BugAsync() ICriteria icriteria = criteria.GetExecutableCriteria(session); icriteria.SetFirstResult(0); icriteria.SetMaxResults(2); - Assert.That(2, Is.EqualTo((await (icriteria.ListAsync())).Count)); + Assert.That((await (icriteria.ListAsync())).Count, Is.EqualTo(2)); } using (ISession session = OpenSession()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs index c9fad064581..3183f6ac993 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1452/Fixture.cs @@ -20,7 +20,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs index c1643f9a028..ae3d6fa4b33 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs @@ -205,7 +205,6 @@ protected override void OnTearDown() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.SqlExceptionConverter, typeof (SQLUpdateConflictToStaleStateExceptionConverter).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index a98b448d4a9..34dec017aa4 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -24,7 +24,6 @@ public class NativeSqlCollectionLoaderFixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.UseQueryCache, WithQueryCache.ToString()); } @@ -244,7 +243,7 @@ public async Task LoadEntityCollectionWithCustomLoaderAsync() [Test] public async Task NativeUpdateQueryWithoutResultsAsync() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -259,7 +258,7 @@ public async Task NativeUpdateQueryWithoutResultsAsync() [Test] public async Task NativeScalarQueryWithoutResultsAsync() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -278,7 +277,7 @@ public async Task NativeScalarQueryWithUndefinedResultsetAsync() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { @@ -301,7 +300,7 @@ public async Task NativeScalarQueryWithDefinedResultsetAsync() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs index 44a2c9f957c..469bad0eb6d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1679/Fixture.cs @@ -64,7 +64,7 @@ protected override void OnTearDown() action.Invoke(criteria); IList l = await (criteria.GetExecutableCriteria(session).ListAsync(cancellationToken)); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs index 63de1264791..2fbaf5b2351 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1688/Fixture.cs @@ -73,7 +73,7 @@ protected override void OnTearDown() action.Invoke(criteria); IList l = await (criteria.GetExecutableCriteria(session).ListAsync(cancellationToken)); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs index 689c84707e9..1d7a0faa961 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1821/Fixture.cs @@ -41,13 +41,9 @@ from Entity Regex whitespaces = new Regex(@"\s+", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); - Assert.AreEqual( - string.Compare( - whitespaces.Replace(sql, " ").Trim(), - whitespaces.Replace(renderedSql, " ").Trim(), - true - ), - 0 + Assert.That( + whitespaces.Replace(renderedSql, " ").Trim(), + Is.EqualTo(whitespaces.Replace(sql, " ").Trim()).IgnoreCase ); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs index a30b6a2a669..c5dc5444b8e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1859/SampleTest.cs @@ -44,7 +44,7 @@ public async Task NativeQueryWithTwoCommentsAsync() IQuery qry = session.CreateSQLQuery("select /* first comment */ o.* /* second comment*/ from domainclass o") .AddEntity("o", typeof (DomainClass)); var res = await (qry.ListAsync()); - Assert.AreEqual(res[0].Id, 1); + Assert.AreEqual(1, res[0].Id); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs index 3f90814e610..e14abf73457 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs @@ -30,7 +30,6 @@ protected override void Configure(Configuration configuration) { listener }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs index 48f8bf99ba5..92b05b1c650 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1989/Fixture.cs @@ -31,7 +31,6 @@ protected override bool AppliesTo(ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs index 8d061a5b768..4d475edc44e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2043/Fixture.cs @@ -30,7 +30,6 @@ public override string GetEntityName(object entity) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(new Namer()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs index 37e4fe39bc0..f4462e5589d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2055/Fixture.cs @@ -27,12 +27,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) return (dialect is Dialect.MsSql2000Dialect); } - protected override void Configure(Configuration configuration) - { - base.Configure(configuration); - cfg = configuration; - } - [Test] public async Task CanCreateAndDropSchemaAsync() { diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs index d963532aa81..dfa2b97b05f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2092/Fixture.cs @@ -38,7 +38,7 @@ public async Task ConstrainedLazyLoadedOneToOneUsingCastleProxyAsync() Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.False); - Assert.That("Person1", Is.EqualTo(employee.Person.Name)); + Assert.That(employee.Person.Name, Is.EqualTo("Person1")); Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.True); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs index 84072f3b7ee..05478d74fba 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2093/Fixture.cs @@ -87,7 +87,7 @@ public async Task CanUseFieldInterceptingProxyAsHQLArgumentAsync() .SetEntity("p", person) .ListAsync()); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); } } finally diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs index c6fa377a043..77c3127e73f 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2174/Fixture.cs @@ -25,8 +25,10 @@ protected override void OnSetUp() { var doc = new Document {Id_Base = 1, Id_Doc = 2}; session.Save(doc); - session.Save(new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}); + var detail = new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}; + session.Save(detail); + doc.RefferedDetailsManyToMany.Add(detail); transaction.Commit(); } } @@ -53,6 +55,14 @@ public async Task LinqFetchAsync() } } + [Test(Description = "GH-3239")] + public async Task LinqFetchManyToManyAsync() + { + using var session = OpenSession(); + var result = await (session.Query().Fetch(x => x.RefferedDetailsManyToMany).FirstAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public async Task QueryOverFetchAsync() { @@ -63,6 +73,14 @@ public async Task QueryOverFetchAsync() } } + [Test(Description = "GH-3239")] + public async Task QueryOverFetchManyToManyAsync() + { + using var session = OpenSession(); + var result = await (session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefaultAsync()); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public async Task LazyLoadAsync() { @@ -73,5 +91,13 @@ public async Task LazyLoadAsync() Assert.That(result.RefferedDetails.Count, Is.EqualTo(1)); } } + + [Test] + public async Task LazyLoadManyToManyAsync() + { + using var session = OpenSession(); + var result = await (session.Query().FirstAsync()); + Assert.That(result.RefferedDetailsManyToMany.Count, Is.EqualTo(1)); + } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index 2d379ed23f5..8a1297d09e9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -102,7 +102,7 @@ public async Task MultiCriteriaQueriesWithIntsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying IntData using (ISession session = this.OpenSession()) @@ -131,7 +131,7 @@ public async Task MultiCriteriaQueriesWithStringsShouldExecuteCorrectlyAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying StringData using (ISession session = this.OpenSession()) diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs index 49fb2b1ccd9..03ff2ce2f05 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2302/Fixture.cs @@ -9,6 +9,7 @@ using System.Data; +using NHibernate.Cfg; using NHibernate.Dialect; using NHibernate.Driver; using NHibernate.Mapping; @@ -17,30 +18,30 @@ namespace NHibernate.Test.NHSpecificTest.NH2302 { - using System.Threading.Tasks; - [TestFixture] - public class FixtureAsync : BugTestCase - { - protected override void Configure(Cfg.Configuration configuration) + using System.Threading.Tasks; + [TestFixture] + public class FixtureAsync : BugTestCase + { + protected override void AddMappings(Configuration configuration) { + base.AddMappings(configuration); + foreach (var cls in configuration.ClassMappings) { foreach (var prop in cls.PropertyIterator) { foreach (var col in prop.ColumnIterator) { - if (col is Column) + if (col is Column column && column.SqlType == "nvarchar(max)") { - var column = col as Column; - if (column.SqlType == "nvarchar(max)") - column.SqlType = Dialect.GetLongestTypeName(DbType.String); + column.SqlType = Dialect.GetLongestTypeName(DbType.String); } } } } } - protected override void OnTearDown() + protected override void OnTearDown() { CleanUp(); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs index 59a1d3d2cea..9a53bc89d6e 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs @@ -25,7 +25,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty("linqtohql.generatorsregistry", "NHibernate.Test.NHSpecificTest.NH2318.ExtendedLinqtoHqlGeneratorsRegistry, NHibernate.Test"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs index 21019688492..479a108ca91 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2439/NH2439Fixture.cs @@ -22,7 +22,6 @@ public class NH2439FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs index 89b6b3be7bd..b5cc0370e13 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2554/Fixture.cs @@ -25,7 +25,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) protected override void Configure(NHibernate.Cfg.Configuration configuration) { configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "keywords"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs index d13589002f3..4eab3ee0a50 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2660And2661/Test.cs @@ -49,7 +49,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { // to be sure we are using the new drive - base.Configure(configuration); configuration.DataBaseIntegration(x=> x.Driver()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs index c3b2d51436a..9bfe3713a02 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2869/Fixture.cs @@ -23,7 +23,6 @@ public class FixtureAsync : BugTestCase protected override void Configure(Configuration configuration) { configuration.LinqToHqlGeneratorsRegistry(); - base.Configure(configuration); } protected override void OnSetUp() @@ -66,4 +65,4 @@ public async Task CustomExtensionWithConstantArgumentShouldBeIncludedInHqlProjec } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs index ffa0243f311..618064daaeb 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2898/Fixture.cs @@ -22,7 +22,6 @@ public class FixtureAsync : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(BinaryFormatterCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -114,4 +113,4 @@ public async Task SecondLevelCacheWithHqlQueriesAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs index ad960e60d4c..2cb7e05afdb 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs @@ -124,7 +124,7 @@ public async Task ConnectionPoolCorruptionAfterDeadlockAsync(bool distributed, b // // ? This shouldn't happen // - Assert.Fail("Surprising exception when trying to force a deadlock: {0}", x); + Assert.Fail($"Surprising exception when trying to force a deadlock: {x}"); } _log.WarnFormat("Initial session seemingly not deadlocked at attempt {0}", tryCount); @@ -254,11 +254,11 @@ public async Task ConnectionPoolCorruptionAfterDeadlockAsync(bool distributed, b } } - Assert.Fail("{0}; {1} subsequent requests failed.", - missingDeadlock - ? "Deadlock not reported on initial request, and initial request failed" - : "Initial request failed", - subsequentFailedRequests); + Assert.Fail( + missingDeadlock + ? $"Deadlock not reported on initial request, and initial request failed; {subsequentFailedRequests} subsequent requests failed." + : $"Initial request failed; {subsequentFailedRequests} subsequent requests failed."); + } while (tryCount < 3); // // I'll change this to while(true) sometimes so I don't have to keep running the test diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs index 0a66df764a6..07bbfd31c7b 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3058/SampleTest.cs @@ -19,8 +19,6 @@ public class SampleTestAsync : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - configuration.Properties.Add("current_session_context_class", "thread_static"); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs index 386428efd12..c6b733fc8a5 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3142/ChildrenTest.cs @@ -32,7 +32,6 @@ public ChildrenTestAsync(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs index 0cbd29f617b..d0fcc95b676 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3202/Fixture.cs @@ -27,11 +27,11 @@ protected override void Configure(Configuration configuration) if (!(Dialect is MsSql2008Dialect)) Assert.Ignore("Test is for MS SQL Server dialect only (custom dialect)."); - if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)))) + if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)))) Assert.Ignore("Test is for MS SQL Server driver only (custom driver is used)."); - cfg.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); } private OffsetStartsAtOneTestDialect OffsetStartsAtOneTestDialect diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs index afd515c3f44..6feae4bb697 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3426/Fixture.cs @@ -50,8 +50,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is SQLiteDialect) { var connStr = configuration.Properties[Environment.ConnectionString]; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs index be33442597b..af6afac0188 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs @@ -36,7 +36,6 @@ public BatchFetchStyleFixtureAsync(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs index 242e8fc5fd2..4acd25ea77d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3848/Fixture.cs @@ -88,7 +88,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Cache(c => { c.UseQueryCache = true; diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs index d5bbb05a2be..f3a64b9ab29 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3912/ReusableBatcherFixture.cs @@ -47,7 +47,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchStrategy, typeof(OracleDataClientBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs index c074a9df506..c782d087a29 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH3952/Fixture.cs @@ -106,4 +106,4 @@ public static MethodInfo GetMethodDefinition2(Func func, return method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs index b1cf11738ad..4581284ba4d 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostInsertFixture.cs @@ -73,7 +73,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostInsertEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs index f2d2f9fc2ff..4ae7189d1c9 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH4077/PostUpdateFixture.cs @@ -67,7 +67,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostUpdateEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs deleted file mode 100644 index 07df8065629..00000000000 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH750/Fixture.cs +++ /dev/null @@ -1,124 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by AsyncGenerator. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - - -using System; -using NHibernate.Cfg; -using NUnit.Framework; - -namespace NHibernate.Test.NHSpecificTest.NH750 -{ - using System.Threading.Tasks; - [TestFixture] - public class FixtureAsync : BugTestCase - { - protected override void OnTearDown() - { - using (ISession s = Sfi.OpenSession()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - s.Flush(); - } - } - - protected override void Configure(Configuration configuration) - { - configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); - base.Configure(configuration); - } - - [Test] - public async Task DeviceOfDriveAsync() - { - int[] dvSavedId = new int[2]; - Drive dr1 = new Drive("Drive 1"); - Drive dr2 = new Drive("Drive 2"); - Drive dr3 = new Drive("Drive 3"); - Device dv1 = new Device("Device 1"); - Device dv2 = new Device("Device 2"); - using (ISession s = Sfi.OpenSession()) - { - await (s.SaveAsync(dr1)); - await (s.SaveAsync(dr2)); - await (s.SaveAsync(dr3)); - dvSavedId[0] = (int) await (s.SaveAsync(dv1)); - dvSavedId[1] = (int) await (s.SaveAsync(dv2)); - await (s.FlushAsync()); - } - - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); - using (ISession s = Sfi.OpenSession()) - { - dvSavedId[0] = (int) await (s.SaveAsync(dv1)); - dvSavedId[1] = (int) await (s.SaveAsync(dv2)); - await (s.FlushAsync()); - } - dv1 = null; - dv2 = null; - using (ISession s = Sfi.OpenSession()) - { - await (s.DeleteAsync(dr3)); - await (s.FlushAsync()); - dv1 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[0])); - dv2 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[1])); - } - Assert.AreEqual(2, dv1.Drives.Count); - // Verify one is missing - Assert.AreEqual(1, dv2.Drives.Count); - // Verify dv1 unchanged - Assert.IsTrue(dv1.Drives.Contains(dr1)); - Assert.IsTrue(dv1.Drives.Contains(dr2)); - - // Verify dv2 - Assert.IsTrue(dv2.Drives.Contains(dr1)); - Assert.IsFalse(dv2.Drives.Contains(dr3)); - - //Make sure that flush didn't touch not-found="ignore" records for not modified collection - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = await (s.GetAsync(dv2.Id)); - await (s.FlushAsync()); - await (t.CommitAsync()); - } - - await (VerifyResultAsync(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection")); - - //Many-to-many clears collection and recreates it so not-found ignore records are lost - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = await (s.GetAsync(dv2.Id)); - dv2.Drives.Add(dr2); - await (t.CommitAsync()); - } - - await (VerifyResultAsync(2, 2, msg: "modified collection")); - - async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string msg) - { - using (var s = Sfi.OpenSession()) - { - var realCound = Convert.ToInt32( - await (s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") - .SetParameter("id", dv2.Id) - .UniqueResultAsync())); - dv2 = await (s.GetAsync(dv2.Id)); - - Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); - Assert.That(realCound, Is.EqualTo(expectedInDb), msg); - } - } - } - } -} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs new file mode 100644 index 00000000000..362bd7a6f71 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyFixture.cs @@ -0,0 +1,155 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + using System.Threading.Tasks; + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyFixtureAsync : BugTestCase + { + private int id2; + private readonly int _drivesCount; + private int _withTemplateId; + private int ValidDrivesCount => _drivesCount; + + public ManyToManyFixtureAsync(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.DrivesNotIgnored.Count >= _drivesCount) + return; + dv.DrivesNotIgnored.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public async Task QueryOverFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task QueryOverFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.CreateQuery("from Device d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task LazyLoadAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + + var dv2 = await (s.GetAsync(id2)); + + await (NHibernateUtil.InitializeAsync(dv2.DrivesNotIgnored)); + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + // First query for Device, second for Drives collection + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs new file mode 100644 index 00000000000..2889ad0ea64 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -0,0 +1,219 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + using System.Threading.Tasks; + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyNotFoundIgnoreFixtureAsync : BugTestCase + { + private int id1; + private int id2; + private int _drive2Id; + private int _withTemplateId; + private readonly int _drivesCount; + private int ValidDrivesCount => _drivesCount == 0 ? 0 : _drivesCount - 1; + + public ManyToManyNotFoundIgnoreFixtureAsync(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + _drive2Id = (int)s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.Drives.Count >= _drivesCount) + return; + dv.Drives.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public async Task DeviceOfDriveAsync() + { + Device dv1; + Device dv2; + using (ISession s = Sfi.OpenSession()) + { + dv1 = (Device) await (s.LoadAsync(typeof(Device), id1)); + dv2 = (Device) await (s.LoadAsync(typeof(Device), id2)); + await (NHibernateUtil.InitializeAsync(dv1.Drives)); + await (NHibernateUtil.InitializeAsync(dv2.Drives)); + } + + Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); + // Verify one is missing + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + + //Make sure that flush didn't touch not-found="ignore" records for not modified collection + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = await (s.GetAsync(dv2.Id)); + await (s.FlushAsync()); + await (t.CommitAsync()); + } + + await (VerifyResultAsync(expectedInCollection: ValidDrivesCount, expectedInDb: _drivesCount, msg: "not modified collection")); + + // Many-to-many clears collection and recreates it so not-found ignore records are lost + // Note: It's not the case when no valid records are present, so loaded Drives collection is empty + // Just skip this check in this case: + if (_drivesCount < 2) + return; + + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = await (s.GetAsync(dv2.Id)); + dv2.Drives.Add(await (s.LoadAsync(_drive2Id))); + await (t.CommitAsync()); + } + + await (VerifyResultAsync(_drivesCount, _drivesCount, msg: "modified collection")); + + async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string msg) + { + using (var s = Sfi.OpenSession()) + { + var realCound = Convert.ToInt32( + await (s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") + .SetParameter("id", dv2.Id) + .UniqueResultAsync())); + dv2 = await (s.GetAsync(dv2.Id)); + + Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); + Assert.That(realCound, Is.EqualTo(expectedInDb), msg); + } + } + } + + [Test] + public async Task QueryOverFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task QueryOverFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.Drives) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefaultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetchAsync() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = await (s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task HqlFetch2Async() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = await (s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResultAsync()); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public async Task LazyLoadAsync() + { + using var s = OpenSession(); + + var dv2 = await (s.GetAsync(id2)); + using var log = new SqlLogSpy(); + + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs new file mode 100644 index 00000000000..78848ea3659 --- /dev/null +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -0,0 +1,109 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System.Linq; +using NHibernate.Criterion; +using NHibernate.Linq; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + using System.Threading.Tasks; + [TestFixture] + public class ManyToManyThrowsForNotFoundFixtureAsync : BugTestCase + { + private int _id; + private int _withTemplateId; + + protected override void OnSetUp() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv }; + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); + + _id = (int) s.Save(dv); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr); + t.Commit(); + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + } + + [Test] + public async Task LazyLoadAsync() + { + using var s = OpenSession(); + var device = await (s.GetAsync(_id)); + Assert.ThrowsAsync(() => NHibernateUtil.InitializeAsync(device.DrivesNotIgnored)); + } + + [Test] + public void QueryOverFetchAsync() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(_id)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.ThrowsAsync(() => queryOver.SingleOrDefaultAsync()); + } + + [Test] + public void QueryOverFetch2Async() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x=> x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.ThrowsAsync(() => queryOver.SingleOrDefaultAsync()); + } + + [Test] + public void LinqFetchAsync() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.DrivesNotIgnored) + .Where(x => x.Id == _id); + Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync())))); + } + + [Test] + public void LinqFetch2Async() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.Template) + .ThenFetchMany(x => x.DrivesNotIgnored) + .Where(x => x.Id == _withTemplateId); + Assert.ThrowsAsync(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync())))); + } + } +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs index df98794f251..f4c4d9cc279 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH940/NH940Fixture.cs @@ -48,7 +48,7 @@ public async Task BugAsync() } catch (Exception e) { - Assert.Fail("Should have thrown MyException, thrown {0} instead", e); + Assert.Fail($"Should have thrown MyException, thrown {e} instead"); } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs b/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs index 31de09b83e7..e2cb3c1821c 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/Properties/CompositePropertyRefTest.cs @@ -72,7 +72,7 @@ public async Task MappingOuterJoinAsync() Assert.IsNull(p2.Address); Assert.IsNotNull(p.Address); var l = await (s.CreateQuery("from Person").ListAsync()); //pull address references for cache - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsTrue(l.Contains(p) && l.Contains(p2)); } } @@ -86,7 +86,7 @@ public async Task AddressBySequentialSelectAsync() using (s.BeginTransaction()) { var l = await (s.CreateQuery("from Person p order by p.Name").ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsNull(l[0].Address); Assert.IsNotNull(l[1].Address); } @@ -101,7 +101,7 @@ public async Task AddressOuterJoinAsync() using (s.BeginTransaction()) { var l = await (s.CreateQuery("from Person p left join fetch p.Address a order by a.Country").ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); if (l[0].Name.Equals("Max")) { Assert.IsNull(l[0].Address); @@ -146,11 +146,11 @@ public async Task AccountsOuterJoinVerifyInitializationAsync() var l = await (s.CreateQuery("from Person p left join fetch p.Accounts a order by p.Name").ListAsync()); var p0 = l[0]; Assert.IsTrue(NHibernateUtil.IsInitialized(p0.Accounts)); - Assert.AreEqual(p0.Accounts.Count, 1); + Assert.AreEqual(1, p0.Accounts.Count); Assert.AreSame(p0.Accounts.First().User, p0); var p1 = l[1]; Assert.IsTrue(NHibernateUtil.IsInitialized(p1.Accounts)); - Assert.AreEqual(p1.Accounts.Count, 0); + Assert.AreEqual(0, p1.Accounts.Count); } } } diff --git a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index 4e4c3d5c4bc..4268b4948ea 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -54,7 +54,7 @@ public void MultiHqlShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) @@ -96,7 +96,7 @@ public void MultiCriteriaShouldThrowUserExceptionAsync() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) diff --git a/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs b/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs index d3fccab6b8a..c8b15b5379f 100644 --- a/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Async/Naturalid/Immutable/ImmutableNaturalIdFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs b/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs index 578f9cb2d9d..7d0e2729bb6 100644 --- a/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Async/Naturalid/Mutable/MutableNaturalIdFixture.cs @@ -32,9 +32,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs b/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs index db43fd24e57..92bc30bfc3b 100644 --- a/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/JoinedSubclassFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.EFGJoinedSubclass.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs b/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs index 415190895fa..d7941caf38d 100644 --- a/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/OnDeleteFixture.cs @@ -30,7 +30,7 @@ protected override string[] Mappings protected override void Configure(Cfg.Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs b/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs index 9874cb0ce94..8bf34fa99ab 100644 --- a/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs +++ b/src/NHibernate.Test/Async/Ondelete/ParentChildFixture.cs @@ -30,9 +30,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.ParentChild.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs index c33de557a91..cf46df6bd03 100644 --- a/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Async/Pagination/CustomDialectFixture.cs @@ -41,12 +41,12 @@ protected override void Configure(Configuration configuration) // Configure is called before Applies, must check here. if (!(Dialect is MsSql2005Dialect)) Assert.Ignore("Test is for SQL dialect only"); - var driverClass = ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)); + var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)); if (!typeof(SqlClientDriver).IsAssignableFrom(driverClass)) Assert.Ignore("Test is compatible only with Sql Server Client driver connection strings"); - cfg.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); } private CustomMsSqlDialect CustomDialect diff --git a/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs b/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs index 7921e7549da..fb9f4fc180c 100644 --- a/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs +++ b/src/NHibernate.Test/Async/Pagination/PaginationFixture.cs @@ -34,7 +34,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.DefaultBatchFetchSize, "20"); + configuration.SetProperty(Environment.DefaultBatchFetchSize, "20"); } [Test] diff --git a/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs b/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs index 1bb2716733f..435758ac99e 100644 --- a/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs +++ b/src/NHibernate.Test/Async/PropertyRef/ManyToManyPropertyRefFixture.cs @@ -8,20 +8,22 @@ //------------------------------------------------------------------------------ +using System.Linq; using NHibernate.Criterion; +using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.PropertyRef { using System.Threading.Tasks; - [TestFixture] + [TestFixture(Description = "NH-2180 (GH-1214)")] public class ManyToManyPropertyRefFixtureAsync : TestCase { protected override string[] Mappings => new[] { "PropertyRef.ManyToManyWithPropertyRef.hbm.xml" }; protected override string MappingsAssembly => "NHibernate.Test"; - private object _manyAId; + private long _manyAId; protected override void OnSetUp() { @@ -34,7 +36,7 @@ protected override void OnSetUp() var manyB2 = new ManyB { Number = 8, Value = "a value of b2" }; var manyB3 = new ManyB { Number = 12, Value = "a value of b3" }; - _manyAId = session.Save(manyA); + _manyAId = (long) session.Save(manyA); session.Save(manyB1); session.Save(manyB2); session.Save(manyB3); @@ -144,5 +146,20 @@ bei NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueK Assert.That(loadedManyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); } + + [Test] + public async Task LinqFetchAsync() + { + using (var session = OpenSession()) + { + var manyA = (await (session + .Query() + .Where(a => a.Id == _manyAId) + .FetchMany(a => a.ManyBs) + .ToListAsync())) + .First(); + Assert.That(manyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); + } + } } } diff --git a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs index 848ead9056e..e63d4372109 100644 --- a/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/Async/QueryTest/MultiCriteriaFixture.cs @@ -41,8 +41,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs index def3e860c51..2adb9224758 100644 --- a/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/Async/ReadOnly/ReadOnlyVersionedNodes.cs @@ -558,7 +558,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -571,7 +571,7 @@ public async Task MergeDetachedChildWithNewParentCommitWithReadOnlyChildAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); @@ -609,7 +609,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() await (t.CommitAsync()); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -622,8 +622,7 @@ public async Task GetChildMakeReadOnlyThenMergeDetachedChildWithNewParentAsync() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); await (s.DeleteAsync(parent)); diff --git a/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs b/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs index 344109b3954..1c963ebbeb8 100644 --- a/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs +++ b/src/NHibernate.Test/Async/SecondLevelCacheTest/SecondLevelCacheTest.cs @@ -35,7 +35,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -273,4 +272,4 @@ public async Task SecondLevelCacheWithHqlQueriesAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs b/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs index fad2a72a99d..6beef5e6769 100644 --- a/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Custom/CustomSQLSupportTest.cs @@ -59,10 +59,10 @@ public async Task HandSQLAsync() s = OpenSession(); t = s.BeginTransaction(); jboss = (Organization)await (s.GetAsync(typeof(Organization), orgId)); - Assert.AreEqual(jboss.Employments.Count, 2); + Assert.AreEqual(2, jboss.Employments.Count); emp = (Employment)GetFirstItem(jboss.Employments); gavin = emp.Employee; - Assert.AreEqual(gavin.Name, "GAVIN"); + Assert.AreEqual("GAVIN", gavin.Name); Assert.AreEqual(s.GetCurrentLockMode(gavin), LockMode.Upgrade); emp.EndDate = DateTime.Today; Employment emp3 = new Employment(gavin, jboss, "US"); @@ -75,7 +75,7 @@ public async Task HandSQLAsync() IEnumerator iter = (await (s.GetNamedQuery("allOrganizationsWithEmployees").ListAsync())).GetEnumerator(); Assert.IsTrue(iter.MoveNext()); Organization o = (Organization)iter.Current; - Assert.AreEqual(o.Employments.Count, 3); + Assert.AreEqual(3, o.Employments.Count); foreach (Employment e in o.Employments) { diff --git a/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs b/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs index 5e91ba4870b..659f9eb4257 100644 --- a/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Custom/CustomStoredProcSupportTest.cs @@ -26,8 +26,8 @@ public async Task ScalarStoredProcedureAsync() namedQuery.SetInt64("number", 43L); IList list = await (namedQuery.ListAsync()); object[] o = (object[])list[0]; - Assert.AreEqual(o[0], "getAll"); - Assert.AreEqual(o[1], 43L); + Assert.AreEqual("getAll", o[0]); + Assert.AreEqual(43L, o[1]); s.Close(); } @@ -41,16 +41,16 @@ public async Task ParameterHandlingAsync() namedQuery.SetInt64(1, 20L); IList list = await (namedQuery.ListAsync()); object[] o = (Object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); namedQuery = s.GetNamedQuery("paramhandling_mixed"); namedQuery.SetInt64(0, 10L); namedQuery.SetInt64("second", 20L); list = await (namedQuery.ListAsync()); o = (object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); s.Close(); } diff --git a/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs b/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs index ac20468608c..107bfe44729 100644 --- a/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs +++ b/src/NHibernate.Test/Async/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs @@ -24,7 +24,6 @@ protected override string MappingsAssembly protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs index 6beefe2afa8..021c6e6761e 100644 --- a/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs +++ b/src/NHibernate.Test/Async/SqlTest/Query/NativeSQLQueriesFixture.cs @@ -130,7 +130,7 @@ public async Task SQLQueryInterfaceAsync() .AddJoin("emp", "org.employments") .AddJoin("pers", "emp.employee") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); } @@ -146,7 +146,7 @@ public async Task SQLQueryInterfaceAsync() .AddJoin("emp", "org.employments") .SetResultTransformer(new DistinctRootEntityResultTransformer()) .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); await (t.CommitAsync()); s.Close(); @@ -183,7 +183,7 @@ public async Task SQLQueryInterfaceCacheableAsync() .AddJoin("pers", "emp.employee") .SetCacheable(true) .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); } @@ -200,7 +200,7 @@ public async Task SQLQueryInterfaceCacheableAsync() .SetCacheable(true) .SetResultTransformer(new DistinctRootEntityResultTransformer()) .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); await (t.CommitAsync()); s.Close(); @@ -478,12 +478,12 @@ public async Task ResultSetMappingDefinitionAsync() IList l = await (s.CreateSQLQuery(OrgEmpRegionSQL) .SetResultSetMapping("org-emp-regionCode") .ListAsync()); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); l = await (s.CreateSQLQuery(OrgEmpPersonSQL) .SetResultSetMapping("org-emp-person") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.CommitAsync()); s.Close(); @@ -522,12 +522,12 @@ public async Task ScalarValuesAsync() IEnumerator iter = (await (s.GetNamedQuery("orgNamesAndOrgs").ListAsync())).GetEnumerator(); iter.MoveNext(); object[] o = (object[]) iter.Current; - Assert.AreEqual(o[0], "IFA"); - Assert.AreEqual(((Organization) o[1]).Name, "IFA"); + Assert.AreEqual("IFA", o[0]); + Assert.AreEqual("IFA", ((Organization) o[1]).Name); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[0], "JBoss"); - Assert.AreEqual(((Organization) o[1]).Name, "JBoss"); + Assert.AreEqual("JBoss", o[0]); + Assert.AreEqual("JBoss", ((Organization) o[1]).Name); await (t.CommitAsync()); s.Close(); @@ -542,13 +542,13 @@ public async Task ScalarValuesAsync() Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); Assert.AreEqual("IFA", ((Organization) row[0]).Name); - Assert.AreEqual(row[1], "IFA"); + Assert.AreEqual("IFA", row[1]); iter.MoveNext(); row = (object[]) iter.Current; Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); - Assert.AreEqual(((Organization) row[0]).Name, "JBoss"); - Assert.AreEqual(row[1], "JBoss"); + Assert.AreEqual("JBoss", ((Organization) row[0]).Name); + Assert.AreEqual("JBoss", row[1]); Assert.IsFalse(iter.MoveNext()); await (t.CommitAsync()); @@ -560,11 +560,11 @@ public async Task ScalarValuesAsync() iter = (await (s.GetNamedQuery("orgIdsAndOrgNames").ListAsync())).GetEnumerator(); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "IFA"); + Assert.AreEqual("IFA", o[1]); Assert.AreEqual(o[0], idIfa); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "JBoss"); + Assert.AreEqual("JBoss", o[1]); Assert.AreEqual(o[0], idJBoss); await (t.CommitAsync()); @@ -713,7 +713,7 @@ public async Task AutoDetectAliasingAsync() IQuery queryWithCollection = s.GetNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.SetInt64("id", jboss.Id); list = await (queryWithCollection.ListAsync()); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); s.Clear(); @@ -804,7 +804,7 @@ public async Task MixAndMatchEntityScalarAsync() IList l = await (s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech") .SetResultSetMapping("speech") .ListAsync()); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); await (t.RollbackAsync()); s.Close(); @@ -883,7 +883,7 @@ public async Task CanSetResultTransformerOnFutureQueryAsync() .SetResultTransformer(transformer) .Future(); - Assert.AreEqual((await (l.GetEnumerableAsync())).Count(), 1); + Assert.AreEqual(1, (await (l.GetEnumerableAsync())).Count()); Assert.AreEqual("Ricardo", (await (l.GetEnumerableAsync())).ElementAt(0)[0]); Assert.IsTrue(transformer.TransformListCalled); Assert.IsTrue(transformer.TransformTupleCalled); @@ -928,7 +928,7 @@ public async Task CanExecuteFutureListAsync() .CreateSQLQuery("select Name from Person") .Future(); - Assert.AreEqual((await (l.GetEnumerableAsync())).Count(), 1); + Assert.AreEqual(1, (await (l.GetEnumerableAsync())).Count()); Assert.AreEqual("Ricardo", (await (l.GetEnumerableAsync())).ElementAt(0)); } } diff --git a/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs b/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs index dc3c2189754..5f520fd4590 100644 --- a/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs +++ b/src/NHibernate.Test/Async/Stateless/StatelessSessionQueryFixture.cs @@ -31,8 +31,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Environment.MaxFetchDepth, 1.ToString()); + configuration.SetProperty(Environment.MaxFetchDepth, 1.ToString()); } protected override bool AppliesTo(Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Async/SubclassFilterTest/JoinedSubclassFilterTest.cs b/src/NHibernate.Test/Async/SubclassFilterTest/JoinedSubclassFilterTest.cs index 83ffbfd159e..d6bebc33ce8 100644 --- a/src/NHibernate.Test/Async/SubclassFilterTest/JoinedSubclassFilterTest.cs +++ b/src/NHibernate.Test/Async/SubclassFilterTest/JoinedSubclassFilterTest.cs @@ -8,7 +8,6 @@ //------------------------------------------------------------------------------ -using System; using System.Collections; using NUnit.Framework; using System.Linq; @@ -17,29 +16,36 @@ namespace NHibernate.Test.SubclassFilterTest { using System.Threading.Tasks; - using System.Threading; [TestFixture] public class JoinedSubclassFilterTestAsync : TestCase { - protected override string[] Mappings + protected override string[] Mappings => new[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; + + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override void OnSetUp() { - get { return new string[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + PrepareTestData(s); + t.Commit(); } - protected override string MappingsAssembly + protected override void OnTearDown() { - get { return "NHibernate.Test"; } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.Delete("from Customer c where c.ContactOwner is not null"); + s.Delete("from Employee e where e.Manager is not null"); + s.Delete("from Person"); + t.Commit(); } [Test] public async Task FiltersWithSubclassAsync() { - ISession s = OpenSession(); + using var s = OpenSession(); s.EnableFilter("region").SetParameter("userRegion", "US"); - ITransaction t = s.BeginTransaction(); - - await (PrepareTestDataAsync(s)); - s.Clear(); IList results; @@ -62,14 +68,6 @@ public async Task FiltersWithSubclassAsync() } s.Clear(); - // TODO : currently impossible to define a collection-level filter w/ - // joined-subclass elements that will filter based on a superclass - // column and function correctly in (theta only?) outer joins; - // this is consistent with the behaviour of a collection-level where. - // this might be one argument for "pulling" the attached class-level - // filters into collection assocations, - // although we'd need some way to apply the appropriate alias in that - // scenario. results = (await (s.CreateQuery("from Person as p left join fetch p.Minions").ListAsync())).Distinct().ToList(); Assert.AreEqual(4, results.Count, "Incorrect qry result count"); foreach (Person p in results) @@ -95,25 +93,12 @@ public async Task FiltersWithSubclassAsync() break; } } - - await (t.CommitAsync()); - s.Close(); - - s = OpenSession(); - t = s.BeginTransaction(); - await (s.DeleteAsync("from Customer c where c.ContactOwner is not null")); - await (s.DeleteAsync("from Employee e where e.Manager is not null")); - await (s.DeleteAsync("from Person")); - await (t.CommitAsync()); - s.Close(); } [Test] public async Task FilterCollectionWithSubclass1Async() { using var s = OpenSession(); - using var t = s.BeginTransaction(); - await (PrepareTestDataAsync(s)); s.EnableFilter("minionsWithManager"); @@ -122,14 +107,10 @@ public async Task FilterCollectionWithSubclass1Async() Assert.That(employees[0].Minions.Count, Is.EqualTo(2)); } - [KnownBug("GH-3079: Collection filter on subclass columns")] - [Test] + [Test(Description = "GH-3079: Collection filter on subclass columns")] public async Task FilterCollectionWithSubclass2Async() { using var s = OpenSession(); - using var t = s.BeginTransaction(); - await (PrepareTestDataAsync(s)); - s.EnableFilter("minionsRegion").SetParameter("userRegion", "US"); var employees = await (s.Query().Where(x => x.Minions.Any()).ToListAsync()); @@ -137,7 +118,7 @@ public async Task FilterCollectionWithSubclass2Async() Assert.That(employees[0].Minions.Count, Is.EqualTo(1)); } - private static async Task PrepareTestDataAsync(ISession s, CancellationToken cancellationToken = default(CancellationToken)) + private static void PrepareTestData(ISession s) { Employee john = new Employee("John Doe"); john.Company = ("JBoss"); @@ -170,11 +151,9 @@ public async Task FilterCollectionWithSubclass2Async() ups.Company = ("UPS"); ups.Region = ("US"); - await (s.SaveAsync(john, cancellationToken)); - await (s.SaveAsync(cust, cancellationToken)); - await (s.SaveAsync(ups, cancellationToken)); - - await (s.FlushAsync(cancellationToken)); + s.Save(john); + s.Save(cust); + s.Save(ups); } } } diff --git a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs index 63543fd6f07..87848c08536 100644 --- a/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/Async/SubselectFetchTest/SubselectFetchFixture.cs @@ -20,9 +20,9 @@ namespace NHibernate.Test.SubselectFetchTest [TestFixture] public class SubselectFetchFixtureAsync : TestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] @@ -55,24 +55,24 @@ public async Task SubselectFetchHqlAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -120,24 +120,24 @@ public async Task SubselectFetchNamedParamAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -185,24 +185,24 @@ public async Task SubselectFetchPosParamAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -251,8 +251,8 @@ public async Task SubselectFetchWithLimitAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(0, p.MoreChildren.Count); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); @@ -261,8 +261,8 @@ public async Task SubselectFetchWithLimitAsync() r = (Parent) await (s.GetAsync(typeof(Parent), r.Name)); Assert.IsTrue(NHibernateUtil.IsInitialized(r.Children)); // The test for True is the test of H3.2 Assert.IsFalse(NHibernateUtil.IsInitialized(r.MoreChildren)); - Assert.AreEqual(r.Children.Count, 1); - Assert.AreEqual(r.MoreChildren.Count, 0); + Assert.AreEqual(1, r.Children.Count); + Assert.AreEqual(0, r.MoreChildren.Count); await (s.DeleteAsync(p)); await (s.DeleteAsync(q)); @@ -344,24 +344,24 @@ public async Task SubselectFetchCriteriaAsync() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); diff --git a/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs b/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs index 7973f10aa17..772522d5131 100644 --- a/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs +++ b/src/NHibernate.Test/Async/SystemTransactions/DistributedSystemTransactionFixture.cs @@ -528,10 +528,11 @@ public async Task CanUseSessionOutsideOfScopeAfterScopeAsync(bool explicitFlush) } var count = 0; Assert.DoesNotThrowAsync(async () => count = await (s.Query().CountAsync()), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } diff --git a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs index 056ae272b0a..a234b0e178f 100644 --- a/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/Async/SystemTransactions/SystemTransactionFixture.cs @@ -9,6 +9,7 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -30,6 +31,13 @@ public class SystemTransactionFixtureAsync : SystemTransactionFixtureBase protected override bool UseConnectionOnSystemTransactionPrepare => true; protected override bool AutoJoinTransaction => true; + protected override void OnTearDown() + { + base.OnTearDown(); + // The SupportsTransactionTimeout test may change this, restore it to its default value. + FailOnNotClosedSession = true; + } + [Test] public async Task WillNotCrashOnPrepareFailureAsync() { @@ -288,10 +296,11 @@ public async Task CanUseSessionOutsideOfScopeAfterScopeAsync(bool explicitFlush) } var count = 0; Assert.DoesNotThrowAsync(async () => count = await (s.Query().CountAsync()), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } @@ -524,6 +533,151 @@ public async Task EnforceConnectionUsageRulesOnTransactionCompletionAsync() // Currently always forbidden, whatever UseConnectionOnSystemTransactionEvents. Assert.That(interceptor.AfterException, Is.TypeOf()); } + + // This test check a concurrency issue hard to reproduce. If it is flaky, it has to be considered failing. + // In such case, raise triesCount to investigate it locally with more chances of triggering the trouble. + [Test] + public async Task SupportsTransactionTimeoutAsync() + { + Assume.That(TestDialect.SupportsTransactionScopeTimeouts, Is.True, "The tested dialect is not supported for transaction scope timeouts."); + // Other special cases: ODBC and SAP SQL Anywhere succeed this test only with transaction.ignore_session_synchronization_failures + // enabled. + // They freeze the session during the transaction cancellation. To avoid the test to be very long, the synchronization + // lock timeout should be lowered too. + + // A concurrency issue exists with the legacy setting allowing to use the session from transaction completion, which + // may cause session leaks. Ignore them. + FailOnNotClosedSession = !UseConnectionOnSystemTransactionPrepare; + + // Test case adapted from https://github.com/kaksmet/NHibBugRepro + + // Create some test data. + const int entitiesCount = 5000; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < entitiesCount; i++) + { + var person = new Person + { + NotNullData = Guid.NewGuid().ToString() + }; + + await (s.SaveAsync(person)); + } + + await (t.CommitAsync()); + } + + // Setup unhandled exception catcher. + _unhandledExceptions = new ConcurrentBag(); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + try + { + // Generate transaction timeouts. + const int triesCount = 100; + var txOptions = new TransactionOptions { Timeout = TimeSpan.FromMilliseconds(1) }; + var timeoutsCount = 0; + for (var i = 0; i < triesCount; i++) + { + try + { + using var txScope = new TransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled); + using var session = OpenSession(); + var data = await (session.CreateCriteria().ListAsync()); + Assert.That(data, Has.Count.EqualTo(entitiesCount), "Unexpected count of loaded entities."); + await (Task.Delay(2)); + var count = await (session.Query().CountAsync()); + Assert.That(count, Is.EqualTo(entitiesCount), "Unexpected entities count."); + txScope.Complete(); + } + catch + { + // Assume that is a transaction timeout. It may cause various failures, of which some are hard to identify. + timeoutsCount++; + } + // If in need of checking some specific failures, the following code may be used instead: + /* + catch (Exception ex) + { + var currentEx = ex; + // Depending on where the transaction aborption has broken NHibernate processing, we may + // get various exceptions, like directly a TransactionAbortedException with an inner + // TimeoutException, or a HibernateException encapsulating a TransactionException with a + // timeout, ... + bool isTransactionException, isTimeout; + do + { + isTransactionException = currentEx is System.Transactions.TransactionException; + isTimeout = isTransactionException && currentEx is TransactionAbortedException; + currentEx = currentEx.InnerException; + } + while (!isTransactionException && currentEx != null); + while (!isTimeout && currentEx != null) + { + isTimeout = currentEx is TimeoutException; + currentEx = currentEx?.InnerException; + } + + if (!isTimeout) + { + // We may also get a GenericADOException with an InvalidOperationException stating the + // transaction associated to the connection is no more active but not yet suppressed, + // and that for executing some SQL, we need to suppress it. That is a weak way of + // identifying the case, especially with the many localizations of the message. + currentEx = ex; + do + { + isTimeout = currentEx is InvalidOperationException && currentEx.Message.Contains("SQL"); + currentEx = currentEx?.InnerException; + } + while (!isTimeout && currentEx != null); + } + + if (isTimeout) + timeoutsCount++; + else + throw; + } + */ + } + + Assert.That( + _unhandledExceptions.Count, + Is.EqualTo(0), + $"Unhandled exceptions have occurred: {string.Join(@" + +", _unhandledExceptions)}"); + + // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly + // more than 10% of the attempts. + Warn.Unless(timeoutsCount, Is.GreaterThan(5), "The test should have generated more timeouts."); + } + finally + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + } + } + + private ConcurrentBag _unhandledExceptions; + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception exception) + { + // Ascertain NHibernate is involved. Some unhandled exceptions occur due to the + // TransactionScope timeout operating on an unexpected thread for the data provider. + var isNHibernateInvolved = false; + while (exception != null && !isNHibernateInvolved) + { + isNHibernateInvolved = exception.StackTrace != null && exception.StackTrace.ToLowerInvariant().Contains("nhibernate"); + exception = exception.InnerException; + } + if (!isNHibernateInvolved) + return; + } + _unhandledExceptions.Add(e.ExceptionObject); + } } [TestFixture] diff --git a/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs b/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs index 3e719891bfe..3de1d4f3ea4 100644 --- a/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs +++ b/src/NHibernate.Test/Async/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs @@ -64,7 +64,7 @@ protected override void CreateSchema() { // Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider // viewer. - Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); Console.WriteLine("Creating the schema failed, assuming it already exists."); Console.WriteLine(ex); } @@ -113,7 +113,7 @@ public async Task ShouldVerifyAsync() } catch (SchemaValidationException sve) { - Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve); + Assert.Fail($"Validation failed: {StringHelper.CollectionToString(sve.ValidationErrors)}.\n{sve}"); } } } diff --git a/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs b/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs index 0c2466f902f..e6af17d146c 100644 --- a/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs +++ b/src/NHibernate.Test/Async/TypeParameters/TypeParameterTest.cs @@ -83,7 +83,7 @@ public async Task SaveAsync() "Default value should have been mapped to null"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_TWO")) == DBNull.Value, "Default value should have been mapped to null"); - Assert.AreEqual(Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), 5, + Assert.AreEqual(5, Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), "Non-Default value should not be changed"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_FOUR")) == DBNull.Value, "Default value should have been mapped to null"); @@ -105,17 +105,17 @@ public async Task LoadingAsync() Widget obj = (Widget) await (s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-normal").UniqueResultAsync()); - Assert.AreEqual(obj.ValueOne, 7, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 8, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, 9, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, 10, "Non-Default value incorrectly loaded"); + Assert.AreEqual(7, obj.ValueOne, "Non-Default value incorrectly loaded"); + Assert.AreEqual(8, obj.ValueTwo, "Non-Default value incorrectly loaded"); + Assert.AreEqual(9, obj.ValueThree, "Non-Default value incorrectly loaded"); + Assert.AreEqual(10, obj.ValueFour, "Non-Default value incorrectly loaded"); obj = (Widget) await (s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-default").UniqueResultAsync()); - Assert.AreEqual(obj.ValueOne, 1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 2, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, -1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, -5, "Default value incorrectly loaded"); + Assert.AreEqual(1, obj.ValueOne, "Default value incorrectly loaded"); + Assert.AreEqual(2, obj.ValueTwo, "Default value incorrectly loaded"); + Assert.AreEqual(-1, obj.ValueThree, "Default value incorrectly loaded"); + Assert.AreEqual(-5, obj.ValueFour, "Default value incorrectly loaded"); await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs index 4588e8d1017..b3cbca7e1e3 100644 --- a/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/AbstractDateTimeTypeFixture.cs @@ -40,8 +40,6 @@ public abstract class AbstractDateTimeTypeFixtureAsync : TypeFixtureBase protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; @@ -69,14 +67,10 @@ protected override void OnSetUp() protected override void OnTearDown() { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); - t.Commit(); - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); + t.Commit(); } protected override void DropSchema() diff --git a/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs index 85b11c47f27..04d2b18b22e 100644 --- a/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/BooleanTypeFixture.cs @@ -8,6 +8,7 @@ //------------------------------------------------------------------------------ +using System; using System.Data.Common; using NHibernate.Engine; using NHibernate.Type; diff --git a/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs new file mode 100644 index 00000000000..4ec37748718 --- /dev/null +++ b/src/NHibernate.Test/Async/TypesTest/CultureInfoTypeFixture.cs @@ -0,0 +1,105 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by AsyncGenerator. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + + +using System; +using System.Globalization; +using NHibernate.Dialect; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.TypesTest +{ + using System.Threading.Tasks; + [TestFixture] + public class CultureInfoTypeFixtureAsync : TypeFixtureBase + { + protected override string TypeName => "CultureInfo"; + + [Test] + public async Task ReadWriteBasicCultureAsync() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US") }; + await (s.SaveAsync(entity)); + id = entity.Id; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture, Is.Not.Null); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("en-US")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US"))); + entity.BasicCulture = CultureInfo.GetCultureInfo("fr-BE"); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("fr-BE")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("fr-BE"))); + entity.BasicCulture = null; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.BasicCulture, Is.Null); + await (t.CommitAsync()); + } + } + + [Test] + public async Task ReadWriteExtendedCultureAsync() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { ExtendedCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + await (s.SaveAsync(entity)); + id = entity.Id; + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = await (s.GetAsync(id)); + Assert.That(entity.ExtendedCulture, Is.Not.Null); + // Under Windows, it is named en-US-posix, but en-US-POSIX under Linux. + Assert.That(entity.ExtendedCulture.Name, Is.EqualTo("en-US-posix").IgnoreCase); + Assert.That(entity.ExtendedCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US-posix"))); + await (t.CommitAsync()); + } + } + + [Test] + public async Task WriteTooLongCultureAsync() + { + if (Dialect is SQLiteDialect) + Assert.Ignore("SQLite has no length limited string type."); + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + await (s.SaveAsync(entity)); + Assert.That(t.Commit, Throws.Exception); + } + } +} diff --git a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs index 64e62c0e326..6ad79ddbd92 100644 --- a/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DateTimeOffsetTypeFixture.cs @@ -42,8 +42,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) => protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; @@ -69,18 +67,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeOffsetClass").ExecuteUpdate(); - t.Commit(); - } - } - protected override void DropSchema() { (Sfi.ConnectionProvider.Driver as ClientDriverWithParamsStats)?.CleanUp(); @@ -354,6 +340,14 @@ public class DateTimeOffsetTypeWithScaleFixtureAsync : DateTimeOffsetTypeFixture // The timestamp rounding in seeding does not account scale. protected override bool RevisionCheck => false; + protected override void OnTearDown() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete DateTimeOffsetClass").ExecuteUpdate(); + t.Commit(); + } + [Test] public async Task LowerDigitsAreIgnoredAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs index c4ab2a0c6f0..2b5f1ef3c38 100644 --- a/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/DecimalTypeFixture.cs @@ -33,8 +33,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is FirebirdDialect) { configuration.SetProperty(Environment.QueryDefaultCastPrecision, "18"); @@ -54,18 +52,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DecimalClass").ExecuteUpdate(); - t.Commit(); - } - } - [Test] public async Task ReadWriteAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs index 255951b0b7a..1733fd0bce8 100644 --- a/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/EnumStringTypeFixture.cs @@ -40,14 +40,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from EnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public async Task ReadFromLoadAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs index 699ef01850b..06aa32c1ab7 100644 --- a/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/GenericEnumStringTypeFixture.cs @@ -42,14 +42,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from GenericEnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public async Task ReadFromLoadAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs index 9f3a2e6c2a2..af573bacd09 100644 --- a/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/GuidTypeFixture.cs @@ -83,4 +83,4 @@ public async Task GuidInWhereClauseAsync() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs index a7d74e58e4d..0808ca7e837 100644 --- a/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/StringTypeFixture.cs @@ -26,14 +26,6 @@ protected override string TypeName get { return "String"; } } - protected override void OnTearDown() - { - using (var s = OpenSession()) - { - s.CreateQuery("delete from StringClass").ExecuteUpdate(); - } - } - [Test] public async Task InsertNullValueAsync() { diff --git a/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs b/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs index 134fdee1b32..f9c585d7956 100644 --- a/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs +++ b/src/NHibernate.Test/Async/TypesTest/TimeAsTimeSpanTypeFixture.cs @@ -50,18 +50,6 @@ protected override string TypeName get { return "TimeAsTimeSpan"; } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var tx = s.BeginTransaction()) - { - s.CreateQuery("delete from TimeAsTimeSpanClass").ExecuteUpdate(); - tx.Commit(); - } - } - [Test] public async Task SavingAndRetrievingAsync() { diff --git a/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs b/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs index d8a2c5ea89c..303012d48b0 100644 --- a/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs +++ b/src/NHibernate.Test/Async/Unionsubclass/DatabaseKeywordsFixture.cs @@ -30,8 +30,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs b/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs index 21d783bac12..05def0554b6 100644 --- a/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs +++ b/src/NHibernate.Test/Async/Unionsubclass/UnionSubclassFixture.cs @@ -66,7 +66,7 @@ public async Task UnionSubclassCollectionAsync() using (ITransaction t = s.BeginTransaction()) { Human gavin = (Human)await (s.CreateCriteria(typeof(Human)).UniqueResultAsync()); - Assert.AreEqual(gavin.Info.Count, 2); + Assert.AreEqual(2, gavin.Info.Count); await (s.DeleteAsync(gavin)); await (s.DeleteAsync(gavin.Location)); await (t.CommitAsync()); diff --git a/src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs b/src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs similarity index 73% rename from src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs rename to src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs index ff1e2011664..99fcfedf320 100644 --- a/src/NHibernate.Test/Async/UtilityTest/LinkedHashMapFixture.cs +++ b/src/NHibernate.Test/Async/UtilityTest/LinkHashMapFixture.cs @@ -9,6 +9,7 @@ using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; @@ -19,17 +20,21 @@ namespace NHibernate.Test.UtilityTest { using System.Threading.Tasks; [TestFixture] - public class LinkedHashMapFixtureAsync + public class LinkHashMapFixtureAsync { - private static readonly Player[] players = { - new Player("12341", "Boeta Dippenaar"), new Player("23432", "Gary Kirsten"), - new Player("23411", "Graeme Smith"), new Player("55221", "Jonty Rhodes"), - new Player("61234", "Monde Zondeki"), new Player("23415", "Paul Adams") - }; + private static readonly Player[] players = + { + new Player("12341", "Boeta Dippenaar"), + new Player("23432", "Gary Kirsten"), + new Player("23411", "Graeme Smith"), + new Player("55221", "Jonty Rhodes"), + new Player("61234", "Monde Zondeki"), + new Player("23415", "Paul Adams") + }; private static void Fill(IDictionary lhm) { - foreach (Player player in players) + foreach (var player in players) lhm.Add(player.Id, player); } @@ -37,11 +42,11 @@ private static void Fill(IDictionary lhm) public async Task ShowDiffAsync() { IDictionary dict = new Dictionary(); - IDictionary lhm = new LinkedHashMap(); + IDictionary lhm = new LinkHashMap(); Fill(dict); Fill(lhm); // Override the first element - Player o = new Player("12341", "Ovirride"); + var o = new Player("12341", "Override"); dict[o.Id] = o; lhm[o.Id] = o; await (Console.Out.WriteLineAsync("Dictionary order:")); @@ -49,7 +54,7 @@ public async Task ShowDiffAsync() { Console.Out.WriteLine("Key->{0}", pair.Key); } - await (Console.Out.WriteLineAsync("LinkedHashMap order:")); + await (Console.Out.WriteLineAsync("LinkHashMap order:")); foreach (KeyValuePair pair in lhm) { Console.Out.WriteLine("Key->{0}", pair.Key); @@ -65,18 +70,18 @@ public async Task PerformanceAsync() int numOfEntries = Int16.MaxValue; - long[] dictPopulateTicks = new long[numOfRuns]; - long[] dictItemTicks = new long[numOfRuns]; + var dictPopulateTicks = new long[numOfRuns]; + var dictItemTicks = new long[numOfRuns]; - long[] linkPopulateTicks = new long[numOfRuns]; - long[] linkItemTicks = new long[numOfRuns]; + var linkPopulateTicks = new long[numOfRuns]; + var linkItemTicks = new long[numOfRuns]; - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) { string key; object value; IDictionary dictionary = new Dictionary(); - IDictionary linked = new LinkedHashMap(); + IDictionary linked = new LinkHashMap(); long dictStart = DateTime.Now.Ticks; @@ -118,12 +123,12 @@ public async Task PerformanceAsync() linked.Clear(); } - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) { decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); - string message = string.Format("LinkedHashMap vs Dictionary (Run-{0}) :",runIndex+1); + string message = string.Format("LinkHashMap vs Dictionary (Run-{0}) :",runIndex+1); message += "\n POPULATE:"; message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; diff --git a/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs b/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs index fe5a770c4c9..b3ec27add5f 100644 --- a/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs +++ b/src/NHibernate.Test/Async/VersionTest/Db/DbVersionFixture.cs @@ -52,6 +52,7 @@ public async System.Threading.Tasks.Task CollectionVersionAsync() admin = await (s.GetAsync(admin.Id)); guy.Groups.Add(admin); admin.Users.Add(guy); + guy.NoOptimisticLock = "changed"; await (t.CommitAsync()); s.Close(); diff --git a/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs b/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs index 78a298f9d0c..b47e8e6f856 100644 --- a/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs +++ b/src/NHibernate.Test/Async/VersionTest/VersionFixture.cs @@ -48,7 +48,7 @@ public async System.Threading.Tasks.Task VersionShortCircuitFlushAsync() await (t.CommitAsync()); s.Close(); - Assert.AreEqual(passp.Version, 2); + Assert.AreEqual(2, passp.Version); s = OpenSession(); t = s.BeginTransaction(); diff --git a/src/NHibernate.Test/BulkManipulation/Course.cs b/src/NHibernate.Test/BulkManipulation/Course.cs new file mode 100644 index 00000000000..0ceb699b8f6 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Course.cs @@ -0,0 +1,8 @@ +namespace NHibernate.Test.BulkManipulation +{ + public class Course + { + public virtual long CourseId { get; set; } + public virtual string Description { get; set; } + } +} diff --git a/src/NHibernate.Test/BulkManipulation/Enrolment.cs b/src/NHibernate.Test/BulkManipulation/Enrolment.cs new file mode 100644 index 00000000000..547ecd52640 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Enrolment.cs @@ -0,0 +1,12 @@ +using System; + +namespace NHibernate.Test.BulkManipulation +{ + [Serializable] + public class Enrolment + { + public virtual long EnrolmentId { get; set; } + public virtual Student Student { get; set; } + public virtual Course Course { get; set; } + } +} diff --git a/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml b/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml new file mode 100644 index 00000000000..84e6a0b293d --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Enrolment.hbm.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs b/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs index 66883da2301..4338c5148b5 100644 --- a/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs +++ b/src/NHibernate.Test/BulkManipulation/HQLBulkOperations.cs @@ -32,5 +32,21 @@ public void SimpleDelete() tx.Commit(); } } + + [Test] + public void InsertFromSelectWithMultipleAssociations() + { + Assume.That(TestDialect.NativeGeneratorSupportsBulkInsertion, + "The dialect does not support a native generator compatible with bulk insertion."); + + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + + s.CreateQuery("insert into Enrolment (Course, Student)" + + " select e.Course, e.Student from Enrolment e") + .ExecuteUpdate(); + + tx.Commit(); + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs index f6b7887b665..fda256b835a 100644 --- a/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs +++ b/src/NHibernate.Test/BulkManipulation/NativeSQLBulkOperationsWithCache.cs @@ -22,9 +22,9 @@ public class NativeSQLBulkOperationsWithCache : TestCase protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.CacheProvider, typeof(SubstituteCacheProvider).AssemblyQualifiedName); } [Test] diff --git a/src/NHibernate.Test/BulkManipulation/Student.cs b/src/NHibernate.Test/BulkManipulation/Student.cs new file mode 100644 index 00000000000..6dd9468adf3 --- /dev/null +++ b/src/NHibernate.Test/BulkManipulation/Student.cs @@ -0,0 +1,8 @@ +namespace NHibernate.Test.BulkManipulation +{ + public class Student + { + public virtual long StudentId { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs index 150369306b2..d3f06568cd6 100644 --- a/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs +++ b/src/NHibernate.Test/CacheTest/BatchableCacheFixture.cs @@ -1553,8 +1553,79 @@ public void QueryFetchEntityBatchCacheTest(bool clearEntityCacheAfterQuery, bool Assert.That(Sfi.Statistics.QueryCacheHitCount, Is.EqualTo(future ? 2 : 1), "Unexpected cache hit count"); } + [Test] + public void CollectionLazyInitializationFromCacheIsBatched() + { + using (var s = OpenSession()) + { + var readOnly = s.Get(s.Query().Select(x => x.Id).First()); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + + using (var s = OpenSession()) + { + var readOnly = s.Get(s.Query().Select(x => x.Id).First()); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + + [Test] + public void CollectionLazyInitializationFromCacheIsBatched_FillCacheByQueryCache() + { + var itemPersister = Sfi.GetEntityPersister(typeof(ReadOnlyItem).FullName); + var itemCache = (BatchableCache) itemPersister.Cache.Cache; + itemCache.ClearStatistics(); + int id; + using (var s = OpenSession()) + { + id = s.Query().Select(x => x.Id).First(); + var readOnly = s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToList() + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + using (var s = OpenSession()) + { + var readOnly = s.Query().Fetch(x => x.Items) + .Where(x => x.Id == id) + .WithOptions(x => x.SetCacheable(true)) + .ToList() + .First(); + Assert.That(itemCache.PutMultipleCalls.Count, Is.EqualTo(0)); + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(readOnly.Items)); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + itemCache.ClearStatistics(); + + + using (var s = OpenSession()) + { + var readOnly = s.Get(id); + Assert.That(readOnly.Items.Count, Is.EqualTo(6)); + } + + // 6 items with batch-size = 4 so 2 GetMany calls are expected 1st call: 4 items + 2nd call: 2 items + Assert.That(itemCache.GetMultipleCalls.Count, Is.EqualTo(2)); + } + private void AssertMultipleCacheCalls(IEnumerable loadIds, IReadOnlyList getIds, int idIndex, - int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null) + int[][] fetchedIdIndexes, int[] putIdIndexes, Func cacheBeforeLoadFn = null) where TEntity : CacheEntity { var persister = Sfi.GetEntityPersister(typeof(TEntity).FullName); diff --git a/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs b/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs index 267b74d015a..3adccdf0f53 100644 --- a/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs +++ b/src/NHibernate.Test/CacheTest/SyncOnlyCacheFixture.cs @@ -11,10 +11,9 @@ namespace NHibernate.Test.CacheTest [TestFixture] public class SyncOnlyCacheFixture : CacheFixture { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CacheReadWriteLockFactory, "sync"); + configuration.SetProperty(Environment.CacheReadWriteLockFactory, "sync"); } [Test] diff --git a/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs b/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs new file mode 100644 index 00000000000..8b5b55f7cb9 --- /dev/null +++ b/src/NHibernate.Test/CacheTest/TextReaderExtensions.cs @@ -0,0 +1,15 @@ +#if !NET8_0_OR_GREATER +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace NHibernate.Test.CacheTest; + +internal static class TextReaderExtensions +{ + public static Task ReadToEndAsync(this TextReader reader, CancellationToken cancellationToken) => + cancellationToken.IsCancellationRequested + ? Task.FromCanceled(cancellationToken) + : reader.ReadToEndAsync(); +} +#endif diff --git a/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs b/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs index 06d190ba08c..1773d6448f5 100644 --- a/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs +++ b/src/NHibernate.Test/Cascade/Circle/MultiPathCircleCascadeTest.cs @@ -42,7 +42,6 @@ protected override string[] Mappings protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs b/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs index 86a91e709d8..e2192233234 100644 --- a/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs +++ b/src/NHibernate.Test/CompositeId/CompositeIdFixture.cs @@ -187,8 +187,8 @@ public void MultipleCollectionFetch() Assert.AreEqual(2, c.Orders.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[0]).LineItems)); Assert.IsTrue(NHibernateUtil.IsInitialized(((Order) c.Orders[1]).LineItems)); - Assert.AreEqual(((Order) c.Orders[0]).LineItems.Count, 2); - Assert.AreEqual(((Order) c.Orders[1]).LineItems.Count, 2); + Assert.AreEqual(2, ((Order) c.Orders[0]).LineItems.Count); + Assert.AreEqual(2, ((Order) c.Orders[1]).LineItems.Count); t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs index bc0df5c5a65..0111d194ae6 100644 --- a/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs +++ b/src/NHibernate.Test/ConnectionTest/AggressiveReleaseTest.cs @@ -12,13 +12,12 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class AggressiveReleaseTest : ConnectionManagementTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.ReleaseConnections, "after_transaction"); - //cfg.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); - //cfg.SetProperty(Environment.GenerateStatistics, "true"); - cfg.SetProperty(Environment.BatchSize, "0"); + configuration.SetProperty(Environment.ReleaseConnections, "after_transaction"); + //configuration.SetProperty(Environment.ConnectionProvider, typeof(DummyConnectionProvider).AssemblyQualifiedName); + //configuration.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.BatchSize, "0"); } protected override ISession GetSessionUnderTest() diff --git a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs index 18e4fcec7da..d11c69f711c 100644 --- a/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/AsyncLocalSessionContextFixture.cs @@ -17,8 +17,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, "async_local"); + configuration.SetProperty(Environment.CurrentSessionContextClass, "async_local"); } [Test] @@ -58,9 +57,7 @@ private void AssertCurrentSession(ISession session, string message) Assert.That( Sfi.GetCurrentSession(), Is.EqualTo(session), - "{0} {1} instead of {2}.", message, - Sfi.GetCurrentSession().GetSessionImplementation().SessionId, - session.GetSessionImplementation().SessionId); + $"{message} {Sfi.GetCurrentSession().GetSessionImplementation().SessionId} instead of {session.GetSessionImplementation().SessionId}."); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs b/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs index d96a7c205d5..b887d83a440 100644 --- a/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/BatcherFixture.cs @@ -11,10 +11,9 @@ namespace NHibernate.Test.ConnectionTest [TestFixture] public class BatcherFixture : ConnectionManagementTestCase { - protected override void Configure(Configuration config) + protected override void Configure(Configuration configuration) { - base.Configure(config); - config.SetProperty(Environment.BatchSize, "10"); + configuration.SetProperty(Environment.BatchSize, "10"); } protected override ISession GetSessionUnderTest() @@ -42,4 +41,4 @@ public void CanCloseCommandsAndUseBatcher() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs b/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs index b22dcd6cd25..73a0bdce75b 100644 --- a/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs +++ b/src/NHibernate.Test/ConnectionTest/CustomCurrentSessionTest.cs @@ -17,8 +17,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof(CustomContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof(CustomContext).AssemblyQualifiedName); } protected override void Release(ISession session) diff --git a/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs index bd4fa61e38a..1893a2be2e9 100644 --- a/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/MapBasedSessionContextFixture.cs @@ -19,8 +19,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof(TestableMapBasedSessionContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof(TestableMapBasedSessionContext).AssemblyQualifiedName); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs b/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs index afd05fab790..59fafad6390 100644 --- a/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs +++ b/src/NHibernate.Test/ConnectionTest/ThreadLocalCurrentSessionTest.cs @@ -17,9 +17,8 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, typeof (TestableThreadLocalContext).AssemblyQualifiedName); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.CurrentSessionContextClass, typeof (TestableThreadLocalContext).AssemblyQualifiedName); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void Release(ISession session) diff --git a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs index 5967e9bf626..7ec9bef8e68 100644 --- a/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs +++ b/src/NHibernate.Test/ConnectionTest/ThreadStaticSessionContextFixture.cs @@ -19,8 +19,7 @@ protected override ISession GetSessionUnderTest() protected override void Configure(Configuration configuration) { - base.Configure(cfg); - cfg.SetProperty(Environment.CurrentSessionContextClass, "thread_static"); + configuration.SetProperty(Environment.CurrentSessionContextClass, "thread_static"); } [Test] @@ -79,9 +78,7 @@ private void AssertCurrentSession(ISessionFactory factory, ISession session, str Assert.That( factory.GetCurrentSession(), Is.EqualTo(session), - "{0} {1} instead of {2}.", message, - factory.GetCurrentSession().GetSessionImplementation().SessionId, - session.GetSessionImplementation().SessionId); + $"{message} {factory.GetCurrentSession().GetSessionImplementation().SessionId} instead of {session.GetSessionImplementation().SessionId}."); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs index 63a22533aa1..2b27d8a2120 100644 --- a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs @@ -3216,7 +3216,7 @@ public void CanSetLockModeOnDetachedCriteria() var countExec = CriteriaTransformer.TransformToRowCount(ec); var countRes = countExec.UniqueResult(); - Assert.AreEqual(countRes, 1); + Assert.AreEqual(1, countRes); } } } diff --git a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs index dd23c4b91b4..17f5ae5a169 100644 --- a/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs +++ b/src/NHibernate.Test/Criteria/Lambda/IntegrationFixture.cs @@ -346,7 +346,7 @@ public void MultiCriteria() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); SetupPagingData(); diff --git a/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs b/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs index 19ad76bc17b..c32811972ec 100644 --- a/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs +++ b/src/NHibernate.Test/Criteria/Lambda/LambdaFixtureBase.cs @@ -81,7 +81,7 @@ private void AssertDictionariesAreEqual(IDictionary expected, IDictionary actual foreach (object key in expected.Keys) { if (!actual.Contains(key)) - Assert.AreEqual(key, null, _fieldPath.Peek() + "[" + key.ToString() + "]"); + Assert.AreEqual(null, key, _fieldPath.Peek() + "[" + key.ToString() + "]"); AssertObjectsAreEqual(expected[key], actual[key], "[" + key.ToString() + "]"); } diff --git a/src/NHibernate.Test/Criteria/ProjectionsTest.cs b/src/NHibernate.Test/Criteria/ProjectionsTest.cs index 0eb03b33a60..1e79dfd92ff 100644 --- a/src/NHibernate.Test/Criteria/ProjectionsTest.cs +++ b/src/NHibernate.Test/Criteria/ProjectionsTest.cs @@ -80,7 +80,7 @@ public void UsingSqlFunctions_Concat_WithCast() { if(Dialect is Oracle8iDialect) { - Assert.Ignore("Not supported by the active dialect:{0}.", Dialect); + Assert.Ignore($"Not supported by the active dialect:{Dialect}."); } if (TestDialect.HasBrokenTypeInferenceOnSelectedParameters) Assert.Ignore("Current dialect does not support this test"); diff --git a/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs b/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs index 749a5184354..7c4e17de210 100644 --- a/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs +++ b/src/NHibernate.Test/Criteria/ReadonlyTests/QueryOverCacheableTests.cs @@ -16,7 +16,6 @@ protected override void Configure(Configuration config) { config.SetProperty(Environment.UseQueryCache, "true"); config.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(config); } [Test] diff --git a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs index a23d9f1d833..652207aa15b 100644 --- a/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs +++ b/src/NHibernate.Test/Criteria/SelectModeTest/SelectModeTest.cs @@ -336,7 +336,7 @@ public void SelectModeFetchLazyPropertiesForEntityJoin() Assert.That(NHibernateUtil.IsInitialized(rootChild), Is.True); Assert.That(NHibernateUtil.IsInitialized(parentJoin), Is.True); - Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.Not.Null.Or.Empty); + Assert.That(NHibernateUtil.IsPropertyInitialized(parentJoin, nameof(parentJoin.LazyProp)), Is.True); Assert.That(parentJoin.LazyProp, Is.Not.Null.Or.Empty); Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1), "Only one SQL select is expected"); @@ -694,7 +694,7 @@ public void FetchModeEagerForEager() private void SkipFutureTestIfNotSupported() { if (Sfi.ConnectionProvider.Driver.SupportsMultipleQueries == false) - Assert.Ignore("Driver {0} does not support multi-queries", Sfi.ConnectionProvider.Driver.GetType().FullName); + Assert.Ignore($"Driver {Sfi.ConnectionProvider.Driver.GetType().FullName} does not support multi-queries"); } #region Test Setup diff --git a/src/NHibernate.Test/DebugSessionFactory.cs b/src/NHibernate.Test/DebugSessionFactory.cs index 7eb551bb83f..8c5d892b1d4 100644 --- a/src/NHibernate.Test/DebugSessionFactory.cs +++ b/src/NHibernate.Test/DebugSessionFactory.cs @@ -43,14 +43,13 @@ public partial class DebugSessionFactory : ISessionFactoryImplementor /// it debug or not. /// public DebugConnectionProvider DebugConnectionProvider - => _debugConnectionProvider ?? - (_debugConnectionProvider = ActualFactory.ConnectionProvider as DebugConnectionProvider); + => _debugConnectionProvider ??= ActualFactory.ConnectionProvider as DebugConnectionProvider; public ISessionFactoryImplementor ActualFactory { get; } public EventListeners EventListeners => ((SessionFactoryImpl)ActualFactory).EventListeners; [NonSerialized] - private readonly ConcurrentBag _openedSessions = new ConcurrentBag(); + private readonly ConcurrentQueue _openedSessions = new(); private static readonly ILog _log = LogManager.GetLogger(typeof(DebugSessionFactory).Assembly, typeof(TestCase)); public DebugSessionFactory(ISessionFactory actualFactory) @@ -63,29 +62,43 @@ public DebugSessionFactory(ISessionFactory actualFactory) public bool CheckSessionsWereClosed() { var allClosed = true; + var number = 1; foreach (var session in _openedSessions) { - // Do not inverse, we want to close all of them. - allClosed = CheckSessionWasClosed(session) && allClosed; + var wasClosed = CheckSessionWasClosed(session); + // No early exit out of the loop: we want to close all forgotten sessions. + if (!wasClosed) + { + _log.ErrorFormat("Test case didn't close session {0}, n°{1} of {2}, closing.", + session.SessionId, number, _openedSessions.Count); + } + allClosed = wasClosed && allClosed; + // Catches only session opened from another one while sharing the connection. Those // opened without sharing the connection stay un-monitored. foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList()) { - allClosed = CheckSessionWasClosed(dependentSession) && allClosed; + wasClosed = CheckSessionWasClosed(dependentSession); + if (!wasClosed) + { + _log.ErrorFormat("Test case didn't close dependent session {0} of the session {3}, n°{1} of {2}, closing.", + dependentSession.SessionId, number, _openedSessions.Count, session.SessionId); + } + allClosed = wasClosed && allClosed; } + number++; } return allClosed; } - private bool CheckSessionWasClosed(ISessionImplementor session) + private static bool CheckSessionWasClosed(ISessionImplementor session) { session.TransactionContext?.Wait(); if (!session.IsOpen) return true; - _log.Error($"Test case didn't close session {session.SessionId}, closing"); (session as ISession)?.Close(); (session as IStatelessSession)?.Close(); return false; @@ -101,7 +114,7 @@ ISession ISessionFactory.OpenSession(DbConnection connection) #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(connection); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -110,7 +123,7 @@ ISession ISessionFactory.OpenSession(IInterceptor sessionLocalInterceptor) #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(sessionLocalInterceptor); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -119,14 +132,14 @@ ISession ISessionFactory.OpenSession(DbConnection conn, IInterceptor sessionLoca #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(conn, sessionLocalInterceptor); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } ISession ISessionFactory.OpenSession() { var s = ActualFactory.OpenSession(); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -138,14 +151,14 @@ IStatelessSessionBuilder ISessionFactory.WithStatelessOptions() IStatelessSession ISessionFactory.OpenStatelessSession() { var s = ActualFactory.OpenStatelessSession(); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } IStatelessSession ISessionFactory.OpenStatelessSession(DbConnection connection) { var s = ActualFactory.OpenStatelessSession(connection); - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -158,7 +171,7 @@ ISession ISessionFactoryImplementor.OpenSession( #pragma warning disable CS0618 // Type or member is obsolete var s = ActualFactory.OpenSession(connection, flushBeforeCompletionEnabled, autoCloseSessionEnabled, connectionReleaseMode); #pragma warning restore CS0618 // Type or member is obsolete - _openedSessions.Add(s.GetSessionImplementation()); + _openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -429,7 +442,7 @@ public SessionBuilder(ISessionBuilder actualBuilder, DebugSessionFactory debugFa ISession ISessionBuilder.OpenSession() { var s = _actualBuilder.OpenSession(); - _debugFactory._openedSessions.Add(s.GetSessionImplementation()); + _debugFactory._openedSessions.Enqueue(s.GetSessionImplementation()); return s; } @@ -504,7 +517,7 @@ public StatelessSessionBuilder(IStatelessSessionBuilder actualBuilder, DebugSess IStatelessSession IStatelessSessionBuilder.OpenStatelessSession() { var s = _actualBuilder.OpenStatelessSession(); - _debugFactory._openedSessions.Add(s.GetSessionImplementation()); + _debugFactory._openedSessions.Enqueue(s.GetSessionImplementation()); return s; } diff --git a/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs index 3e5b162a61a..eaa2016adf7 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2005DialectFixture.cs @@ -357,13 +357,13 @@ private static void VerifyLimitStringForStoredProcedureCalls(string sql) { var d = new MsSql2005Dialect(); var limitSql = d.GetLimitString(new SqlString(sql), null, new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), null); - Assert.That(limitSql, Is.Null, "Offset only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Offset only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit and Offset: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit and Offset: {sql}"); } [Test] diff --git a/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs index e02b69dfed2..3115bf26328 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2008DialectFixture.cs @@ -148,16 +148,7 @@ public void ScaleTypes() Assert.That(dialect.GetTypeName(SqlTypeFactory.GetTime(max + 1)), Is.EqualTo("time").IgnoreCase, "Over max time"); } - private static readonly FieldInfo _mappingField = - typeof(Configuration).GetField("mapping", BindingFlags.Instance | BindingFlags.NonPublic); - - private static IMapping GetMapping(Configuration cfg) - { - Assert.That(_mappingField, Is.Not.Null, "Unable to find field mapping"); - var mapping = _mappingField.GetValue(cfg) as IMapping; - Assert.That(mapping, Is.Not.Null, "Unable to find mapping object"); - return mapping; - } + private static IMapping GetMapping(Configuration cfg) => (IMapping) cfg.BuildSessionFactory(); private static void AssertSqlType(IType type, SqlType sqlType, IMapping mapping) { diff --git a/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs b/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs index 04ebc9c638b..2f7ae070123 100644 --- a/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs +++ b/src/NHibernate.Test/DialectTest/MsSql2012DialectFixture.cs @@ -167,13 +167,13 @@ private static void VerifyLimitStringForStoredProcedureCalls(string sql) { var d = new MsSql2012Dialect(); var limitSql = d.GetLimitString(new SqlString(sql), null, new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), null); - Assert.That(limitSql, Is.Null, "Offset only: {0}", sql); + Assert.That(limitSql, Is.Null, $"Offset only: {sql}"); limitSql = d.GetLimitString(new SqlString(sql), new SqlString("10"), new SqlString("2")); - Assert.That(limitSql, Is.Null, "Limit and Offset: {0}", sql); + Assert.That(limitSql, Is.Null, $"Limit and Offset: {sql}"); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs b/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs index 93034e9dc3d..e673a18adec 100644 --- a/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs +++ b/src/NHibernate.Test/DriverTest/OracleDataClientDriverFixture.cs @@ -121,7 +121,7 @@ private static OracleDataClientDriverBase GetDriver(bool managed, IDictionary(); - Assert.AreEqual(report.AvgPay, 2.5); - Assert.AreEqual(report.MaxPay, 4); - Assert.AreEqual(report.MinPay, 1); + Assert.AreEqual(2.5, report.AvgPay); + Assert.AreEqual(4, report.MaxPay); + Assert.AreEqual(1, report.MinPay); } } @@ -86,10 +86,10 @@ public void QueryTest1() Assert.IsTrue(result[0] is object[], "expected object[] as result, but found " + result[0].GetType().Name); object[] results = (object[])result[0]; - Assert.AreEqual(results.Length, 3); - Assert.AreEqual(results[0], 2.5); - Assert.AreEqual(results[1], 4); - Assert.AreEqual(results[2], 1); + Assert.AreEqual(3, results.Length); + Assert.AreEqual(2.5, results[0]); + Assert.AreEqual(4, results[1]); + Assert.AreEqual(1, results[2]); } } @@ -108,7 +108,7 @@ public void SelectSqlProjectionTest() IList result = c.List(); // c.UniqueResult(); Assert.IsTrue(result.Count == 1); object results = result[0]; - Assert.AreEqual(results, 2.5); + Assert.AreEqual(2.5, results); } } } diff --git a/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs b/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs index 094ca51f000..6c5ed1966ef 100644 --- a/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs +++ b/src/NHibernate.Test/Extralazy/ExtraLazyFixture.cs @@ -103,7 +103,7 @@ public void ListAdd(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after checking existence of non-flushed"); @@ -311,7 +311,7 @@ public void ListInsert(bool initialize) // Have to skip unloaded (non-queued indeed) elements to avoid triggering existence queries on them. foreach (var item in addedItems.Skip(5)) { - Assert.That(gavin.Companies.Contains(item), Is.True, "Company '{0}' existence", item.Name); + Assert.That(gavin.Companies.Contains(item), Is.True, $"Company '{item.Name}' existence"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after existence check"); @@ -625,7 +625,7 @@ public void ListGetSet(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), "Comparing added company at index {0}", i); + Assert.That(gavin.Companies[i], Is.EqualTo(addedItems[i]), $"Comparing added company at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after adding comparing"); @@ -665,7 +665,7 @@ public void ListGetSet(bool initialize) Sfi.Statistics.Clear(); for (var i = 0; i < 10; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company ListIndex at index {i}"); } Assert.That(Sfi.Statistics.FlushCount, Is.EqualTo(0), "Flushes count after comparing"); @@ -787,7 +787,7 @@ public void ListFlush(bool initialize) { for (var i = 15; i < 20; i++) { - Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, "Removing transient company at index {0}", i); + Assert.That(gavin.Companies.Remove(addedItems[i]), Is.True, $"Removing transient company at index {i}"); } Assert.That(FindAllOccurrences(sqlLog.GetWholeLog(), "INSERT \n INTO"), Is.EqualTo(10), "Statements count after removing"); @@ -898,7 +898,7 @@ public void ListFlush(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), "Comparing company ListIndex at index {0}", i); + Assert.That(gavin.Companies[i].ListIndex, Is.EqualTo(i), $"Comparing company ListIndex at index {i}"); } if (initialize) @@ -1038,7 +1038,7 @@ public void ListClear(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Credit cards count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, "Checking existence for item at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence for item at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Credit cards initialization status after loading again"); @@ -1129,7 +1129,7 @@ public void ListIndexOperations(bool initialize) for (var i = 0; i < gavin.Companies.Count; i++) { - Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), "Comparing company index at {0}", i); + Assert.That(gavin.Companies[i].OriginalIndex, Is.EqualTo(finalIndexOrder[i]), $"Comparing company index at {i}"); } if (initialize) @@ -1871,8 +1871,7 @@ public void SetClear(bool initialize) Assert.That(collection.Count, Is.EqualTo(6), "Permissions count after loading again Gavin"); for (var i = 0; i < 10; i++) { - Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, - "Checking existence of added element at {0}", i); + Assert.That(collection.Contains(addedItems[i]), i < 6 ? Is.True : (IResolveConstraint) Is.False, $"Checking existence of added element at {i}"); } Assert.That(NHibernateUtil.IsInitialized(collection), Is.False, "Permissions initialization status after loading again"); diff --git a/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml b/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml index 2dd3fb6433d..0bd06b06d9e 100644 --- a/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml +++ b/src/NHibernate.Test/Extralazy/UserGroup.hbm.xml @@ -4,7 +4,7 @@ assembly="NHibernate.Test" namespace="NHibernate.Test.Extralazy"> - + diff --git a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs index 43d68dce93d..1fd3b8ed063 100644 --- a/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs +++ b/src/NHibernate.Test/FetchLazyProperties/FetchLazyPropertiesFixture.cs @@ -33,7 +33,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; } @@ -175,6 +174,18 @@ public void TestLinqFetchProperty() AssertFetchProperty(person); } + [Test] + public void TestLinqFetchPropertyAfterSelect() + { + using var s = OpenSession(); + var owner = s.Query() + .Select(a => a.Owner) + .Fetch(o => o.Image) + .FirstOrDefault(o => o.Id == 1); + + AssertFetchProperty(owner); + } + private static void AssertFetchProperty(Person person) { Assert.That(person, Is.Not.Null); @@ -265,6 +276,45 @@ public void TestLinqFetchAllProperties() AssertFetchAllProperties(person); } + [TestCase(true)] + [TestCase(false)] + public void TestLinqFetchAllProperties_WhenLazyPropertyChanged(bool initLazyPropertyFetchGroup) + { + Person person; + using (var s = OpenSession()) + { + person = s.Get(1); + if (initLazyPropertyFetchGroup) + CollectionAssert.AreEqual(new byte[] { 0 }, person.Image); + + person.Image = new byte[] { 1, 2, 3 }; + + var allPersons = s.Query().FetchLazyProperties().ToList(); + // After execute FetchLazyProperties(), I expected to see that the person.Image would be { 1, 2, 3 }. + // Because I changed this person.Image manually, I didn't want to lose those changes. + // But test failed. Оld value returned { 0 }. + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image); + } + } + + [TestCase(true)] + [TestCase(false)] + public void TestLinqFetchProperty_WhenLazyPropertyChanged(bool initLazyPropertyFetchGroup) + { + Person person; + using (var s = OpenSession()) + { + person = s.Get(1); + if (initLazyPropertyFetchGroup) + CollectionAssert.AreEqual(new byte[] { 0 }, person.Image); + + person.Image = new byte[] { 1, 2, 3 }; + + var allPersons = s.Query().Fetch(x => x.Image).ToList(); + CollectionAssert.AreEqual(new byte[] { 1, 2, 3 }, person.Image); + } + } + private static void AssertFetchAllProperties(Person person) { Assert.That(person, Is.Not.Null); diff --git a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs index edbff2a5a25..67f96306bc1 100644 --- a/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs +++ b/src/NHibernate.Test/FilterTest/DynamicFilterTest.cs @@ -96,7 +96,7 @@ public void CombinedClassAndCollectionFiltersEnabled() salespersons = session.CreateQuery("select s from Salesperson as s left join fetch s.Orders").List(); Assert.AreEqual(1, salespersons.Count, "Incorrect salesperson count"); sp = (Salesperson) salespersons[0]; - Assert.AreEqual(sp.Orders.Count, 1, "Incorrect order count"); + Assert.AreEqual(1, sp.Orders.Count, "Incorrect order count"); } } diff --git a/src/NHibernate.Test/FilterTest/FilterConfig.cs b/src/NHibernate.Test/FilterTest/FilterConfig.cs index 26c5d590aeb..d7e67d8952a 100644 --- a/src/NHibernate.Test/FilterTest/FilterConfig.cs +++ b/src/NHibernate.Test/FilterTest/FilterConfig.cs @@ -15,13 +15,13 @@ public void FilterDefinitionsLoadedCorrectly() { Configuration cfg = new Configuration(); cfg.AddResource(mappingCfg, this.GetType().Assembly); - Assert.AreEqual(cfg.FilterDefinitions.Count, 2); + Assert.AreEqual(2, cfg.FilterDefinitions.Count); Assert.IsTrue(cfg.FilterDefinitions.ContainsKey("LiveFilter")); FilterDefinition f = cfg.FilterDefinitions["LiveFilter"]; - Assert.AreEqual(f.ParameterTypes.Count, 1); + Assert.AreEqual(1, f.ParameterTypes.Count); BooleanType t = f.ParameterTypes["LiveParam"] as BooleanType; @@ -40,7 +40,7 @@ public void FiltersLoaded() IFilter filter = session.EnableFilter("LiveFilter"); - Assert.AreEqual(filter.FilterDefinition.FilterName, "LiveFilter"); + Assert.AreEqual("LiveFilter", filter.FilterDefinition.FilterName); filter.SetParameter("LiveParam", true); diff --git a/src/NHibernate.Test/Futures/FallbackFixture.cs b/src/NHibernate.Test/Futures/FallbackFixture.cs index b7fa34759a7..d9042acc6ce 100644 --- a/src/NHibernate.Test/Futures/FallbackFixture.cs +++ b/src/NHibernate.Test/Futures/FallbackFixture.cs @@ -35,8 +35,7 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - using (var cp = ConnectionProviderFactory.NewConnectionProvider(cfg.Properties)) + using (var cp = ConnectionProviderFactory.NewConnectionProvider(configuration.Properties)) { if (cp.Driver is SqlClientDriver) { diff --git a/src/NHibernate.Test/Futures/FutureFixture.cs b/src/NHibernate.Test/Futures/FutureFixture.cs index ad318651a9d..6cb6401d26d 100644 --- a/src/NHibernate.Test/Futures/FutureFixture.cs +++ b/src/NHibernate.Test/Futures/FutureFixture.cs @@ -20,7 +20,7 @@ protected void IgnoreThisTestIfMultipleQueriesArentSupportedByDriver() { var driver = Sfi.ConnectionProvider.Driver; if (driver.SupportsMultipleQueries == false) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); } protected void CreatePersons() diff --git a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs index 7eb3f8eb7d6..d197c037825 100644 --- a/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs +++ b/src/NHibernate.Test/Generatedkeys/Identity/IdentityGeneratedKeysTest.cs @@ -25,7 +25,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs index 13a3c6e0e7b..70e1e21613e 100644 --- a/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs +++ b/src/NHibernate.Test/GhostProperty/GhostPropertyFixture.cs @@ -260,5 +260,54 @@ public void WillFetchJoinInSingleHqlQuery() Assert.DoesNotThrow(() => { var x = order.Payment; }); } + + [Test(Description = "GH-1267(NH-3047)")] + public void WillFetchJoinInAdditionalHqlQuery() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + order = s.CreateQuery("from Order o where o.Id = 1").List()[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + // ... then join-fetch the related payment + s.CreateQuery("from Order o left join fetch o.Payment where o.Id = 1").List(); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } + + [Test(Description = "GH-1267(NH-3047)")] + public void WillFetchJoinWithCriteria() + { + Order order = null; + + // load the order... + ISession s = OpenSession(); + + var query = s.CreateCriteria(); + query.Add(Criterion.Restrictions.Eq("Id", 1)); + order = query.List()[0]; + s.Disconnect(); + + Assert.Throws(typeof(LazyInitializationException), () => { var y = order.Payment; }); + + s.Reconnect(); + + // ... then join-fetch the related payment + var query2 = s.CreateCriteria(); + query2.Add(Criterion.Restrictions.Eq("Id", 1)); + query2.Fetch(SelectMode.Fetch, "Payment"); + query2.List(); + s.Close(); + + Assert.DoesNotThrow(() => { var x = order.Payment; }); + Assert.That(order.Payment.Type, Is.EqualTo("WT")); + } } } diff --git a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml index 2594f4c5afa..6790652371b 100644 --- a/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml +++ b/src/NHibernate.Test/GhostProperty/Mappings.hbm.xml @@ -19,6 +19,7 @@ + diff --git a/src/NHibernate.Test/GhostProperty/Order.cs b/src/NHibernate.Test/GhostProperty/Order.cs index a0ef5e9a01b..99c0465c1cc 100644 --- a/src/NHibernate.Test/GhostProperty/Order.cs +++ b/src/NHibernate.Test/GhostProperty/Order.cs @@ -18,8 +18,9 @@ public virtual Payment Payment public abstract class Payment { public virtual int Id { get; set; } + public virtual string Type { get; set; } } public class WireTransfer : Payment{} public class CreditCard : Payment { } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Hql/Ast/BulkManipulation.cs b/src/NHibernate.Test/Hql/Ast/BulkManipulation.cs index bb24ff0c228..ff1e0a98299 100644 --- a/src/NHibernate.Test/Hql/Ast/BulkManipulation.cs +++ b/src/NHibernate.Test/Hql/Ast/BulkManipulation.cs @@ -884,7 +884,7 @@ public void SimpleDeleteOnAnimal() { if (Dialect.HasSelfReferentialForeignKeyBug) { - Assert.Ignore("self referential FK bug", "HQL delete testing"); + Assert.Ignore("self referential FK bug - HQL delete testing"); return; } diff --git a/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs b/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs index 45be4789f1c..3af770191d5 100644 --- a/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs +++ b/src/NHibernate.Test/Hql/Ast/ParsingFixture.cs @@ -1,176 +1,137 @@ using System; using System.Collections.Generic; -using log4net.Config; -using NHibernate.Cfg; -using NHibernate.Engine; +using System.IO; +using System.Xml.Linq; using NHibernate.Hql.Ast.ANTLR; -using NHibernate.Tool.hbm2ddl; using NUnit.Framework; namespace NHibernate.Test.Hql.Ast { - // This test need the new NUnit - //[TestFixture] - //public class ParsingFixture - //{ - // /// - // /// Key test for HQL strings -> HQL AST's - takes the query and returns a string - // /// representation of the resultant tree - // /// - // /// - // /// - // [Test] - // [TestCaseSource(typeof(QueryFactoryClass), "TestCases")] - // public string HqlParse(string query) - // { - // // This test need the new NUnit - // var p = new HqlParseEngine(query, false, null); - // p.Parse(); - - // return " " + p.Ast.ToStringTree(); - // } - - // /// - // /// Used to test individual queries "by hand", since td.net doesn't let me run a - // /// single test out of a data set - // /// - // [Test] - // public void ManualTest() - // { - // var p = new HqlParseEngine(@"select all s, s.Other from s in class Simple where s = :s", false, null); - - // p.Parse(); - - // Console.WriteLine(p.Ast.ToStringTree()); - // } - - // /// - // /// Helper "test" to display queries that are ignored - // /// - // [Test] - // public void ShowIgnoredQueries() - // { - // foreach (string query in QueryFactoryClass.GetIgnores) - // { - // Console.WriteLine(query); - // } - // } - - // /// - // /// Helper "test" to display queries that don't parse in H3 - // /// - // [Test] - // public void ShowExceptionQueries() - // { - // foreach (string query in QueryFactoryClass.GetExceptions) - // { - // Console.WriteLine(query); - // } - // } - - // /// - // /// Goes all the way to the DB and back. Just here until there's a better place to put it... - // /// - // [Test] - // public void BasicQuery() - // { - // string input = "select o.id, li.id from NHibernate.Test.CompositeId.Order o join o.LineItems li";// join o.LineItems li"; - - // ISessionFactoryImplementor sfi = SetupSFI(); - - // ISession session = sfi.OpenSession(); - // session.CreateQuery(input).List(); - // /* - // foreach (Animal o in session.CreateQuery(input).Enumerable()) - // { - // Console.WriteLine(o.Description); - // }*/ - // } - - // ISessionFactoryImplementor SetupSFI() - // { - // Configuration cfg = new Configuration(); - // cfg.AddAssembly(this.GetType().Assembly); - // new SchemaExport(cfg).Create(false, true); - // return (ISessionFactoryImplementor)cfg.BuildSessionFactory(); - // } - - // /// - // /// Class used by Nunit 2.5 to drive the data into the HqlParse test - // /// - // public class QueryFactoryClass - // { - // public static IEnumerable TestCases - // { - // get - // { - // // TODO - need to handle Ignore better (it won't show in results...) - // return EnumerateTests(td => !td.Ignore && !td.Result.StartsWith("Exception"), - // td => new TestCaseData(td.Query) - // .Returns(td.Result) - // .SetCategory(td.Category) - // .SetName(td.Name) - // .SetDescription(td.Description)); - // } - // } - - // public static IEnumerable GetIgnores - // { - // get - // { - // return EnumerateTests(td => td.Ignore, - // td => td.Query); - // } - // } - - // public static IEnumerable GetExceptions - // { - // get - // { - // return EnumerateTests(td => td.Result.StartsWith("Exception"), - // td => td.Query); - // } - // } - - // static IEnumerable EnumerateTests(Func predicate, Func projection) - // { - // XDocument doc = XDocument.Load(@"HQL Parsing\TestQueriesWithResults.xml"); - - // foreach (XElement testGroup in doc.Element("Tests").Elements("TestGroup")) - // { - // string category = testGroup.Attribute("Name").Value; - - // foreach (XElement test in testGroup.Elements("Test")) - // { - // QueryTestData testData = new QueryTestData(category, test); - - // if (predicate(testData)) - // { - // yield return projection(testData); - // } - // } - // } - // } - - // class QueryTestData - // { - // internal QueryTestData(string category, XElement xml) - // { - // Category = category; - // Query = xml.Element("Query").Value; - // Result = xml.Element("Result") != null ? xml.Element("Result").Value : "barf"; - // Name = xml.Element("Name") != null ? xml.Element("Name").Value : null; - // Description = xml.Element("Description") != null ? xml.Element("Description").Value : null; - // Ignore = xml.Attribute("Ignore") != null ? bool.Parse(xml.Attribute("Ignore").Value) : false; - // } - - // internal string Category; - // internal string Query; - // internal string Result; - // internal string Name; - // internal string Description; - // internal bool Ignore; - // } - // } - //} + [TestFixture] + public class ParsingFixture + { + /// + /// Key test for HQL strings -> HQL AST's - takes the query and returns a string + /// representation of the resultant tree + /// + /// + /// + [Test] + [TestCaseSource(typeof(QueryFactoryClass), nameof(QueryFactoryClass.TestCases))] + public string HqlParse(string query) + { + var p = new HqlParseEngine(query, false, null); + var result = p.Parse().ToStringTree(); + + return " " + result; + } + + /// + /// Used to test individual queries "by hand", since td.net doesn't let me run a + /// single test out of a data set + /// + [Test, Explicit] + public void ManualTest() + { + var p = new HqlParseEngine(@"select all s, s.Other from s in class Simple where s = :s", false, null); + + var result = p.Parse().ToStringTree(); + + Console.WriteLine(result); + } + + /// + /// Helper "test" to display queries that are ignored + /// + [Test, Explicit] + public void ShowIgnoredQueries() + { + foreach (string query in QueryFactoryClass.GetIgnores) + { + Console.WriteLine(query); + } + } + + /// + /// Helper "test" to display queries that don't parse in H3 + /// + [Test, Explicit] + public void ShowExceptionQueries() + { + foreach (string query in QueryFactoryClass.GetExceptions) + { + Console.WriteLine(query); + } + } + + /// + /// Class used by NUnit to drive the data into the HqlParse test. + /// + public class QueryFactoryClass + { + public static IEnumerable TestCases => + // TODO - need to handle Ignore better (it won't show in results...) + EnumerateTests( + td => !td.Ignore && !td.Result.StartsWith("Exception"), + td => new TestCaseData(td.Query) + .Returns(td.Result) + .SetCategory(td.Category) + .SetName(td.Name) + .SetDescription(td.Description)); + + public static IEnumerable GetIgnores => + EnumerateTests( + td => td.Ignore, + td => td.Query); + + public static IEnumerable GetExceptions => + EnumerateTests( + td => td.Result.StartsWith("Exception"), + td => td.Query); + + static IEnumerable EnumerateTests( + Func predicate, + Func projection) + { + + XDocument doc = XDocument.Load( + Path.Combine(Path.GetDirectoryName(typeof(ParsingFixture).Assembly.Location), @"Hql/Ast/TestQueriesWithResults.xml")); + + foreach (XElement testGroup in doc.Element("Tests").Elements("TestGroup")) + { + string category = testGroup.Attribute("Name").Value; + + foreach (XElement test in testGroup.Elements("Test")) + { + QueryTestData testData = new QueryTestData(category, test); + + if (predicate(testData)) + { + yield return projection(testData); + } + } + } + } + + class QueryTestData + { + internal QueryTestData(string category, XElement xml) + { + Category = category; + Query = xml.Element("Query").Value.Trim(); + Result = xml.Element("Result")?.Value; + Name = xml.Element("Name")?.Value; + Description = xml.Element("Description")?.Value.Trim() ?? string.Empty; + Ignore = bool.Parse(xml.Attribute("Ignore")?.Value ?? "false"); + } + + internal string Category; + internal string Query; + internal string Result; + internal string Name; + internal string Description; + internal bool Ignore; + } + } + } } diff --git a/src/NHibernate.Test/Hql/Ast/TestQueries.xml b/src/NHibernate.Test/Hql/Ast/TestQueries.xml deleted file mode 100644 index 5b0488ae037..00000000000 --- a/src/NHibernate.Test/Hql/Ast/TestQueries.xml +++ /dev/null @@ -1,3006 +0,0 @@ - - - - - all baz.IntArray.indices]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - current_date]]> - - - 100]]> - - - 10000]]> - - - - 100]]> - - - 10000]]> - - - - - - - - - - - - - all elements(p.scores)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 100 - order by count(kitten) asc, sum(kitten.weight) desc - ]]> - - - - - - - = all ( - select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate) group by ord - having sum(price.amount) > :minAmount order by sum(price.amount) desc - ]]> - - - - :minAmount order by sum(price.amount) desc - ]]> - - - - PaymentStatus.AWAITING_APPROVAL or ( - statusChange.timeStamp = ( select max(change.timeStamp) - from PaymentStatusChange change where change.payment = payment - ) and statusChange.user <> :currentUser ) - group by status.name, status.sortOrder order by status.sortOrder - ]]> - - - PaymentStatus.AWAITING_APPROVAL - or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser - group by status.name, status.sortOrder order by status.sortOrder - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ( select avg(cat.weight) from eg.DomesticCat cat)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 3.1415e3]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - parse( - "SELECT DISTINCT bar FROM eg.mypackage.Cat qat left join com.multijoin.JoinORama as bar, com.toadstool.Foo f join net.sf.blurb.Blurb"); - - - - - - - - - - - - - 5]]> - - - 5]]> - - - - - - - - - - - - 10]]> - - - 10 and an.bodyWeight < 100) or an.bodyWeight is null - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Added quote quote is an escape - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - 'a' or foo2.id <'a' - ]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ? or bar.short = 1 or bar.string = 'ff ? bb']]> - - - - - - - - - - - - - - - - - - '0' order by s.foo]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 'a']]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TODO: "count" is reserved - - - - TODO: "count" is reserved - - - - TODO: "count" is reserved - - - - - - - - - - 0]]> - - - 0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 10]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - :count]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0]]> - - - - - - 'a']]> - - - - - - - - - - - - - - - - - - - - - 'a']]> - - - 'a']]> - - - - - - - - - - - - - - - -1 and s.name is null]]> - - - - - - -1 and s.name is null]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0 - ]]> - - - 0 and m.extraProp is not null]]> - - - 0 and m.name is not null]]> - - - - - - - - - 0.0]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Added '?' as a valid expression. - - - - - - - - - Added collectionExpr as a valid 'in' clause. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Cover NOT optimization in HqlParser - - - - - 1 )]]> - - - = 1 )]]> - - - - - - - - - - - - - - - double "NOT" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - -1 and this.name is null]]> - - - from h3.2.6 I'm not sure about these... [jsd] - - - - from h3.2.6 I'm not sure about these... [jsd] - - - - - - - - - - - - - - - no member of - - - - - - - - - - - - - - - - The keyword 'order' used as a property name. - - - - The keyword 'order' and 'count' used as a property name. - 3]]> - - - - The keywords 'where', 'order' and 'count' used as a property name. - 3]]> - - - - - - - - - - - - - Super evil badness... a legitimate keyword! - - - - - - - - - - - - - - - - - - - - - - - - - - Okay, now this is getting silly. - - - - - - - - - - - - - - - 'where' as a package name - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TODO support .NET identifier NH-685; won't fix ? - - - - - - - TODO Some SQLs have function names with package qualifiers. - - - - - - - - - - - - - - - - - won't fix - - :dateenow ]]> - - - - - - - - - - - - - - 1]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - [Test, Ignore("Not supported")] - - - TODO InnerClass but for NET - the problem with inner class is that in .NET the "separator" is '+' and - Path+Identifier is a valid MathAddExpression - because this is a special case and the use of entity-name is a valid workaroud we can wait - to support it or we can choose another character to query inner-classes (the same of JAVA '$' is a valid choice) - - - - - - - - - - - TODO Support Unicode in StringLiteral - - - - - - - - from NHibernate tests - - - - - - - - 1]]> - - - - - - 0]]> - - - - - - 0]]> - - - - - - 0]]> - - - - - - 0]]> - - - - from NHibernate tests - - - - - - - - - - - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - from NHibernate tests - - - - - 0]]> - - - 0]]> - - - - from NHibernate tests - - - - - - - - - - - - - - from NHibernate tests - - - - - 10]]> - - - - - from NHibernate tests - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - from NHibernate tests - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - - - - - - - - - - - - - 0]]> - - - 0]]> - - - 0]]> - - - - - - - - - - - from NHibernate tests - - - - - - - from NHibernate tests - - - - - 0]]> - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - from NHibernate tests - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - - - - - - - - - from NHibernate tests - - 0]]> - - - 3]]> - - - 0]]> - - - - \ No newline at end of file diff --git a/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml b/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml index c7d8efb5a52..03fa3aa7a5e 100644 --- a/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml +++ b/src/NHibernate.Test/Hql/Ast/TestQueriesWithResults.xml @@ -269,14 +269,14 @@ select cat.color, sum(cat.weight), count(cat) from eg.Cat cat group by cat.color having cat.color in (eg.Color.TABBY, eg.Color.BLACK) ]]> - + 100 order by count(kitten) asc, sum(kitten.weight) desc ]]> - ( avg ( . kitten weight ) ) 100 ) ) ) ( order ( count kitten ) asc ( sum ( . kitten weight ) ) desc ) )]]> + ( avg ( . kitten weight ) ) 100 ) ) ( order ( count kitten ) asc ( sum ( . kitten weight ) ) desc ) )]]> @@ -290,7 +290,7 @@ select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate) group by ord having sum(price.amount) > :minAmount order by sum(price.amount) desc ]]> - = ( . catalog effectiveDate ) ( all ( query ( SELECT_FROM ( from ( RANGE Catalog cat ) ) ( select ( . cat effectiveDate ) ) ) ( where ( < ( . cat effectiveDate ) sysdate ) ) ) ) ) ) ) ( group ord ( having ( > ( sum ( . price amount ) ) ( : minAmount ) ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> + = ( . catalog effectiveDate ) ( all ( query ( SELECT_FROM ( from ( RANGE Catalog cat ) ) ( select ( . cat effectiveDate ) ) ) ( where ( < ( . cat effectiveDate ) sysdate ) ) ) ) ) ) ) ( group ord ) ( having ( > ( sum ( . price amount ) ) ( : minAmount ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> :minAmount order by sum(price.amount) desc ]]> - ( sum ( . price amount ) ) ( : minAmount ) ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> + ( sum ( . price amount ) ) ( : minAmount ) ) ) ( order ( sum ( . price amount ) ) desc ) )]]> 10]]> - ( sum ( . s count ) ) 10 ) ) ) )]]> + ( sum ( . s count ) ) 10 ) ) )]]> - + @@ -3510,7 +3510,7 @@ 0]]> - ( ( abs ( exprList ( * ( . a BodyWeight ) ( - 1 ) ) ) ) 0 ) ) ) )]]> + ( ( abs ( exprList ( * ( . a BodyWeight ) ( - 1 ) ) ) ) 0 ) ) )]]> @@ -3551,7 +3551,7 @@ - + @@ -3568,7 +3568,7 @@ - + @@ -3615,15 +3615,15 @@ 0]]> - ( ( cast ( exprList ( . a BodyWeight ) Double ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( . a BodyWeight ) Double ) ) 0 ) ) )]]> 0]]> - ( ( cast ( exprList ( - ( + 7 123.3 ) ( * 1 ( . a BodyWeight ) ) ) int ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( - ( + 7 123.3 ) ( * 1 ( . a BodyWeight ) ) ) int ) ) 0 ) ) )]]> 0]]> - ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) int ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) int ) ) 0 ) ) )]]> @@ -3718,7 +3718,7 @@ 0]]> - ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) Double ) ) 0 ) ) ) )]]> + ( ( cast ( exprList ( + ( : aParam ) ( . a BodyWeight ) ) Double ) ) 0 ) ) )]]> diff --git a/src/NHibernate.Test/Hql/EntityJoinHqlTest.cs b/src/NHibernate.Test/Hql/EntityJoinHqlTest.cs index 4833f1de14f..9c55fbb54d7 100644 --- a/src/NHibernate.Test/Hql/EntityJoinHqlTest.cs +++ b/src/NHibernate.Test/Hql/EntityJoinHqlTest.cs @@ -346,6 +346,15 @@ from x2 in session.Query() //GH-2988 var withNullOrValidList = session.Query().Where(x => x.ManyToOne.Id == validManyToOne.Id || x.ManyToOne == null).ToList(); var withNullOrValidList2 = session.Query().Where(x => x.ManyToOne == null || x.ManyToOne.Id == validManyToOne.Id).ToList(); + //GH-3269 + var invalidId = Guid.NewGuid(); + var withInvalidOrValid = session.Query().Where(x => x.OneToOne.Id == invalidId || x.ManyToOne.Id == validManyToOne.Id).ToList(); + var withInvalidOrNull = session.Query().Where(x => x.ManyToOne.Id == invalidId || x.OneToOne == null).ToList(); + var withInvalidOrNotNull = session.Query().Where(x => x.ManyToOne.Id == invalidId || x.OneToOne != null).ToList(); + + Assert.That(withInvalidOrValid.Count, Is.EqualTo(1)); + Assert.That(withInvalidOrNull.Count, Is.EqualTo(2)); + Assert.That(withInvalidOrNotNull.Count, Is.EqualTo(0)); //GH-3185 var mixImplicitAndLeftJoinList = session.Query().Where(x => x.ManyToOne.Id == validManyToOne.Id && x.OneToOne == null).ToList(); diff --git a/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs new file mode 100644 index 00000000000..9eb0095ea37 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/HqlParserFixture.cs @@ -0,0 +1,30 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Hql.Ast.ANTLR.Tree; +using NUnit.Framework; + +namespace NHibernate.Test.Hql.Parser +{ + [TestFixture] + public class HqlParserFixture + { + [Test] + public void HandlesPathWithReservedWords() + { + Assert.DoesNotThrow(() => Parse("delete from System.Object")); + Assert.DoesNotThrow(() => Parse("delete from Object.Object.Object.Object")); + } + + private static void Parse(string hql) + { + var lex = new HqlLexer(new CaseInsensitiveStringStream(hql)); + var tokens = new CommonTokenStream(lex); + + var parser = new HqlParser(tokens) + { + TreeAdaptor = new ASTTreeAdaptor(), + ParseErrorHandler = new WarningAsErrorReporter() + }.statement(); + } + } +} diff --git a/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs new file mode 100644 index 00000000000..5897d670698 --- /dev/null +++ b/src/NHibernate.Test/Hql/Parser/WarningAsErrorReporter.cs @@ -0,0 +1,29 @@ +using Antlr.Runtime; +using NHibernate.Hql.Ast.ANTLR; + +namespace NHibernate.Test.Hql.Parser +{ + public class WarningAsErrorReporter : IParseErrorHandler + { + public void ReportError(RecognitionException e) + { + throw e; + } + + public void ReportError(string s) + { + throw new QueryException(s); + } + + public void ReportWarning(string s) + { + throw new QueryException(s); + } + + public int GetErrorCount() => 0; + + public void ThrowQueryException() + { + } + } +} diff --git a/src/NHibernate.Test/IdGen/GuidComb/GuidCombFixture.cs b/src/NHibernate.Test/IdGen/GuidComb/GuidCombFixture.cs new file mode 100644 index 00000000000..b79bbb807b1 --- /dev/null +++ b/src/NHibernate.Test/IdGen/GuidComb/GuidCombFixture.cs @@ -0,0 +1,32 @@ +using System; +using NHibernate.Id; +using NUnit.Framework; + +namespace NHibernate.Test.IdGen.GuidComb; + +[TestFixture] +public class GuidCombFixture +{ + class GuidCombGeneratorEx : GuidCombGenerator + { + public static Guid Generate(string guid, DateTime utcNow) => GenerateComb(Guid.Parse(guid), utcNow); + } + + [Test] + public void CanGenerateSequentialGuid() + { + Assert.AreEqual(Guid.Parse("076a04fa-ef4e-4093-8479-b0e10103cdc5"), + GuidCombGeneratorEx.Generate( + "076a04fa-ef4e-4093-8479-8599e96f14cf", + new DateTime(2023, 12, 23, 15, 45, 55, DateTimeKind.Utc)), + "seed: 076a04fa"); + + Assert.AreEqual(Guid.Parse("81162ee2-a4cb-4611-9327-d61f0137e5b6"), + GuidCombGeneratorEx.Generate( + "81162ee2-a4cb-4611-9327-23bbda36176c", + new DateTime(2050, 01, 29, 18, 55, 35, DateTimeKind.Utc)), + "seed: 81162ee2"); + + } + +} diff --git a/src/NHibernate.Test/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs b/src/NHibernate.Test/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs index a3c0c6e8bb8..665072b04d4 100644 --- a/src/NHibernate.Test/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs +++ b/src/NHibernate.Test/IdGen/NativeGuid/NativeGuidGeneratorFixture.cs @@ -31,7 +31,7 @@ public void ReturnedValueIsGuid() } catch (NotSupportedException) { - Assert.Ignore("This test does not apply to {0}", Dialect.Dialect.GetDialect()); + Assert.Ignore($"This test does not apply to {Dialect.Dialect.GetDialect()}"); } var gen = new NativeGuidGenerator(); diff --git a/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs b/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs index 77ade682908..5f623d9652c 100644 --- a/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs +++ b/src/NHibernate.Test/IdTest/UseIdentifierRollbackTest.cs @@ -20,8 +20,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseIdentifierRollBack, "true"); - base.Configure(configuration); + configuration.SetProperty(Environment.UseIdentifierRollBack, "true"); } public void SimpleRollback() diff --git a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs index 1e77060ab44..be22e24c08a 100644 --- a/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs +++ b/src/NHibernate.Test/Immutable/EntityWithMutableCollection/AbstractEntityWithManyToManyTest.cs @@ -485,7 +485,7 @@ public void CreateWithNonEmptyManyToManyCollectionMergeWithNewElement() s.Close(); AssertInsertCount(1); - AssertUpdateCount(isContractVersioned && isPlanVersioned ? 1 : 0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(isContractVersioned && isPlanVersioned ? 2 : 0); ClearCounts(); s = OpenSession(); diff --git a/src/NHibernate.Test/Immutable/ImmutableTest.cs b/src/NHibernate.Test/Immutable/ImmutableTest.cs index 214252925b1..18f476411d9 100644 --- a/src/NHibernate.Test/Immutable/ImmutableTest.cs +++ b/src/NHibernate.Test/Immutable/ImmutableTest.cs @@ -17,7 +17,6 @@ public class ImmutableTest : TestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true"); configuration.SetProperty(NHibernate.Cfg.Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs b/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs index 7f52de482e4..a0ff97f8a70 100644 --- a/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs +++ b/src/NHibernate.Test/LazyGroup/LazyGroupFixture.cs @@ -19,7 +19,6 @@ public class LazyGroupFixture : TestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/LazyProperty/Book.cs b/src/NHibernate.Test/LazyProperty/Book.cs index 546df8a248b..10eb7d241f2 100644 --- a/src/NHibernate.Test/LazyProperty/Book.cs +++ b/src/NHibernate.Test/LazyProperty/Book.cs @@ -17,8 +17,22 @@ public virtual string ALotOfText public virtual byte[] Image { get; set; } + private byte[] _NoSetterImage; + + public virtual byte[] NoSetterImage + { + get { return _NoSetterImage; } + set { _NoSetterImage = value; } + } + public virtual string FieldInterceptor { get; set; } public virtual IList Words { get; set; } + + public virtual int this[int i] + { + get { return i;} + set { } + } } } diff --git a/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs b/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs index 5efb7d6e29d..1b588dee440 100644 --- a/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs +++ b/src/NHibernate.Test/LazyProperty/LazyPropertyFixture.cs @@ -3,6 +3,7 @@ using System.Linq; using NHibernate.Cfg; using NHibernate.Intercept; +using NHibernate.Linq; using NHibernate.Tuple.Entity; using NUnit.Framework; using NUnit.Framework.Constraints; @@ -55,6 +56,7 @@ protected override void OnSetUp() Id = 1, ALotOfText = "a lot of text ...", Image = new byte[10], + NoSetterImage = new byte[10], FieldInterceptor = "Why not that name?" }); tx.Commit(); @@ -223,6 +225,9 @@ public void CanGetValueForNonLazyProperty() Assert.That(book.Name, Is.EqualTo("some name")); Assert.That(book.FieldInterceptor, Is.EqualTo("Why not that name?")); Assert.That(NHibernateUtil.IsPropertyInitialized(book, "ALotOfText"), Is.False); + //GH-3354 Exception accessing indexer property + Assert.That(book[0], Is.EqualTo(0)); + Assert.DoesNotThrow(() => book[0] = 0); } } @@ -385,5 +390,58 @@ public void CanMergeTransientWithLazyPropertyInCollection() Assert.That(book.Words.First().Content, Is.EqualTo(new byte[1] { 0 })); } } + + [Test(Description = "GH-3333")] + public void GetLazyPropertyWithNoSetterAccessor_PropertyShouldBeInitialized() + { + using (ISession s = OpenSession()) + { + var book = s.Get(1); + var image = book.NoSetterImage; + // Fails. Property remains uninitialized after it has been accessed. + Assert.That(NHibernateUtil.IsPropertyInitialized(book, "NoSetterImage"), Is.True); + } + } + + [Test(Description = "GH-3333")] + public void GetLazyPropertyWithNoSetterAccessorTwice_ResultsAreSameObject() + { + using (ISession s = OpenSession()) + { + var book = s.Get(1); + var image = book.NoSetterImage; + var sameImage = book.NoSetterImage; + // Fails. Each call to a property getter returns a new object. + Assert.That(ReferenceEquals(image, sameImage), Is.True); + } + } + + [Test] + public void CanSetValueForLazyPropertyNoSetter() + { + Book book; + using (ISession s = OpenSession()) + { + book = s.Get(1); + book.NoSetterImage = new byte[]{10}; + } + + Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True); + CollectionAssert.AreEqual(book.NoSetterImage, new byte[] { 10 }); + } + + [Test] + public void CanFetchLazyPropertyNoSetter() + { + using (ISession s = OpenSession()) + { + var book = s + .Query() + .Fetch(x => x.NoSetterImage) + .First(x => x.Id == 1); + + Assert.That(NHibernateUtil.IsPropertyInitialized(book, nameof(book.NoSetterImage)), Is.True); + } + } } } diff --git a/src/NHibernate.Test/LazyProperty/Mappings.hbm.xml b/src/NHibernate.Test/LazyProperty/Mappings.hbm.xml index 91189c36e30..533576580cd 100644 --- a/src/NHibernate.Test/LazyProperty/Mappings.hbm.xml +++ b/src/NHibernate.Test/LazyProperty/Mappings.hbm.xml @@ -11,6 +11,7 @@ + diff --git a/src/NHibernate.Test/Legacy/FooBarTest.cs b/src/NHibernate.Test/Legacy/FooBarTest.cs index 9704b5dc737..7dc868b4222 100644 --- a/src/NHibernate.Test/Legacy/FooBarTest.cs +++ b/src/NHibernate.Test/Legacy/FooBarTest.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.Globalization; using System.IO; +using System.Linq; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Text; @@ -1066,8 +1067,8 @@ public void PropertyRef() using (ISession s = OpenSession()) { Holder h = (Holder) s.Load(typeof(Holder), hid); - Assert.AreEqual(h.Name, "foo"); - Assert.AreEqual(h.OtherHolder.Name, "bar"); + Assert.AreEqual("foo", h.Name); + Assert.AreEqual("bar", h.OtherHolder.Name); object[] res = (object[]) s.CreateQuery("from Holder h join h.OtherHolder oh where h.OtherHolder.Name = 'bar'").List()[0]; Assert.AreSame(h, res[0]); @@ -1210,10 +1211,7 @@ public void BatchLoad() s.Delete(baz2); s.Delete(baz3); - IEnumerable en = new JoinedEnumerable( - new IEnumerable[] {baz.FooSet, baz2.FooSet}); - - foreach (object obj in en) + foreach (var obj in baz.FooSet.Concat(baz2.FooSet)) { s.Delete(obj); } @@ -1418,7 +1416,7 @@ public void Sortables() // DictionaryEntry key - not the index. foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } @@ -1434,7 +1432,7 @@ public void Sortables() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } s.Flush(); @@ -1449,7 +1447,7 @@ public void Sortables() Assert.IsTrue(b.Sortablez.Count == 3); foreach (Sortable sortable in b.Sortablez) { - Assert.AreEqual(sortable.name, "bar"); + Assert.AreEqual("bar", sortable.name); break; } s.Delete(b); @@ -5261,16 +5259,13 @@ public void TransientOrphanDelete() Baz baz = new Baz(); var bars = new HashSet { new Bar(), new Bar(), new Bar() }; baz.CascadingBars = bars; - IList foos = new List(); - foos.Add(new Foo()); - foos.Add(new Foo()); + var foos = new List { new Foo(), new Foo() }; baz.FooBag = foos; s.Save(baz); - IEnumerator enumer = new JoinedEnumerable(new IEnumerable[] {foos, bars}).GetEnumerator(); - while (enumer.MoveNext()) + foreach (var foo in foos.Concat(bars.Cast())) { - FooComponent cmp = ((Foo) enumer.Current).Component; + var cmp = foo.Component; s.Delete(cmp.Glarch); cmp.Glarch = null; } diff --git a/src/NHibernate.Test/Legacy/MasterDetailTest.cs b/src/NHibernate.Test/Legacy/MasterDetailTest.cs index d07d30af15a..94d0253eaf9 100644 --- a/src/NHibernate.Test/Legacy/MasterDetailTest.cs +++ b/src/NHibernate.Test/Legacy/MasterDetailTest.cs @@ -183,7 +183,7 @@ public void CopyCascade() // Save parent and cascade update detached child Category persistentParent = s.Merge(parent); Assert.IsTrue(persistentParent.Subcategories.Count == 1); - Assert.AreEqual(((Category) persistentParent.Subcategories[0]).Name, "child2"); + Assert.AreEqual("child2", ((Category) persistentParent.Subcategories[0]).Name); s.Flush(); s.Close(); diff --git a/src/NHibernate.Test/Legacy/SQLLoaderTest.cs b/src/NHibernate.Test/Legacy/SQLLoaderTest.cs index 5818a4f9909..75b4e71d289 100644 --- a/src/NHibernate.Test/Legacy/SQLLoaderTest.cs +++ b/src/NHibernate.Test/Legacy/SQLLoaderTest.cs @@ -520,7 +520,7 @@ private void ComponentTest(string sql) IQuery q = session.CreateSQLQuery(sql).AddEntity("comp", typeof(Componentizable)); IList list = q.List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); Componentizable co = (Componentizable) list[0]; diff --git a/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs b/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs index e576587cc01..b55a87f2d15 100644 --- a/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/AverageTests.cs @@ -13,7 +13,7 @@ public void CanGetAverageOfIntegersAsDouble() //NH-2429 var average = db.Products.Average(x => x.UnitsOnOrder); - Assert.AreEqual(average, 10.129870d, 0.000001d); + Assert.AreEqual(10.129870d, average, 0.000001d); } } } diff --git a/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs b/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs index 7e6258bfcaf..7b83694fcca 100644 --- a/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/GroupByHavingTests.cs @@ -10,7 +10,6 @@ public class GroupByHavingTests : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs b/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs index 01e21c1d1cd..a45b8d18c9f 100644 --- a/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs +++ b/src/NHibernate.Test/Linq/ByMethod/OrderByTests.cs @@ -10,7 +10,6 @@ public class OrderByTests : LinqTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/Linq/EnumTests.cs b/src/NHibernate.Test/Linq/EnumTests.cs index 21adf84bf3a..3a4a8711fef 100644 --- a/src/NHibernate.Test/Linq/EnumTests.cs +++ b/src/NHibernate.Test/Linq/EnumTests.cs @@ -161,13 +161,11 @@ public void ConditionalNavigationProperty() } } - [Test] - public void CanQueryComplexExpressionOnTestEnum() + [TestCase(null)] + [TestCase(TestEnum.Unspecified)] + public void CanQueryComplexExpressionOnTestEnum(TestEnum? type) { - //TODO: Fix issue on SQLite with type set to TestEnum.Unspecified - TestEnum? type = null; using (var session = OpenSession()) - using (var trans = session.BeginTransaction()) { var entities = session.Query(); @@ -184,7 +182,7 @@ public void CanQueryComplexExpressionOnTestEnum() coalesce = user.NullableEnum1 ?? TestEnum.Medium }).ToList(); - Assert.That(query.Count, Is.EqualTo(0)); + Assert.That(query.Count, Is.EqualTo(type == TestEnum.Unspecified ? 1 : 0)); } } diff --git a/src/NHibernate.Test/Linq/FunctionTests.cs b/src/NHibernate.Test/Linq/FunctionTests.cs index b92e7b3ece9..a182169a7bc 100644 --- a/src/NHibernate.Test/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Linq/FunctionTests.cs @@ -192,7 +192,7 @@ where lowerName.IndexOf('a') == 0 select lowerName; var result = query.ToList(); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); ObjectDumper.Write(query); } @@ -208,7 +208,7 @@ where lowerName.IndexOf('a', 2) == -1 select lowerName; var result = query.ToList(); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); ObjectDumper.Write(query); } @@ -224,7 +224,7 @@ where lowerName.IndexOf("an") == 0 select lowerName; var result = query.ToList(); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); ObjectDumper.Write(query); } @@ -240,7 +240,7 @@ where lowerName.Contains("a") select lowerName.IndexOf("a", 1); var result = query.ToList(); - Assert.That(result, Is.EqualTo(expected), "Expected {0} but was {1}", string.Join("|", expected), string.Join("|", result)); + Assert.That(result, Is.EqualTo(expected), $"Expected {string.Join("|", expected)} but was {string.Join("|", result)}"); ObjectDumper.Write(query); } @@ -491,6 +491,33 @@ where item.Discount.Equals(-1) ObjectDumper.Write(query); } + [Test] + public void WhereEnumEqual() + { + var query = from item in db.PatientRecords + where item.Gender.Equals(Gender.Female) + select item; + + ObjectDumper.Write(query); + + query = from item in db.PatientRecords + where item.Gender.Equals(item.Gender) + select item; + + ObjectDumper.Write(query); + } + + + [Test] + public void WhereObjectEqual() + { + var query = from item in db.PatientRecords + where ((object) item.Gender).Equals(Gender.Female) + select item; + + ObjectDumper.Write(query); + } + [Test] public void WhereEquatableEqual() { diff --git a/src/NHibernate.Test/Linq/MethodCallTests.cs b/src/NHibernate.Test/Linq/MethodCallTests.cs index c330b0944da..05abb79c0af 100644 --- a/src/NHibernate.Test/Linq/MethodCallTests.cs +++ b/src/NHibernate.Test/Linq/MethodCallTests.cs @@ -47,6 +47,7 @@ public void CanExecuteCountWithOrderByArguments() public void CanSelectPropertiesIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Name, u.InvalidLoginAttempts}) .First(); @@ -59,6 +60,7 @@ public void CanSelectPropertiesIntoObjectArray() public void CanSelectComponentsIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Component, u.Component.OtherComponent}) .First(); @@ -94,6 +96,7 @@ public void CanSelectConstantsIntoObjectArray() const string name = "Julian"; var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, pi, name, DateTime.MinValue}) .First(); @@ -107,6 +110,7 @@ public void CanSelectConstantsIntoObjectArray() public void CanSelectPropertiesFromAssociationsIntoObjectArray() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new object[] {u.Id, u.Role.Name, u.Role.Entity.Output}) .First(); @@ -119,6 +123,7 @@ public void CanSelectPropertiesFromAssociationsIntoObjectArray() public void CanSelectPropertiesIntoObjectArrayInProperty() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new object[] { u.Id, u.Name, new object[u.Id] } }) .First(); @@ -132,6 +137,7 @@ public void CanSelectPropertiesIntoObjectArrayInProperty() public void CanSelectPropertiesIntoPropertyListInProperty() { var result = db.Users + .OrderBy(u => u.Id) .Select(u => new { Cells = new List { u.Id, u.Name, new object[u.Id] } }) .First(); @@ -144,7 +150,7 @@ public void CanSelectPropertiesIntoPropertyListInProperty() [Test, Description("NH-2744")] public void CanSelectPropertiesIntoNestedObjectArrays() { - var query = db.Users.Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); + var query = db.Users.OrderBy(u => u.Id).Select(u => new object[] {"Root", new object[] {"Sub1", u.Name, new object[] {"Sub2", u.Name}}}); var result = query.First(); Assert.That(result.Length, Is.EqualTo(2)); diff --git a/src/NHibernate.Test/Linq/PagingTests.cs b/src/NHibernate.Test/Linq/PagingTests.cs index b92abec5404..b5cbc78fab2 100644 --- a/src/NHibernate.Test/Linq/PagingTests.cs +++ b/src/NHibernate.Test/Linq/PagingTests.cs @@ -229,7 +229,7 @@ public void Customers11to20() var query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); } @@ -239,19 +239,19 @@ public void Customers11to20And21to30ShouldNoCacheQuery() var query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(10).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(20).Take(10).ToList(); - Assert.AreNotEqual(query[0], "BSBEV"); + Assert.AreNotEqual("BSBEV", query[0]); Assert.AreEqual(10, query.Count); query = (from c in db.Customers orderby c.CustomerId select c.CustomerId).Skip(10).Take(20).ToList(); - Assert.AreEqual(query[0], "BSBEV"); + Assert.AreEqual("BSBEV", query[0]); Assert.AreEqual(20, query.Count); } @@ -276,7 +276,7 @@ public void CustomersChainedSkip() { var q = (from c in db.Customers select c.CustomerId).Skip(10).Skip(5); var query = q.ToList(); - Assert.AreEqual(query[0], "CONSH"); + Assert.AreEqual("CONSH", query[0]); Assert.AreEqual(76, query.Count); } diff --git a/src/NHibernate.Test/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Linq/PreEvaluationTests.cs index 4e12c4b9d82..f0698f15906 100644 --- a/src/NHibernate.Test/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Linq/PreEvaluationTests.cs @@ -24,8 +24,6 @@ public PreEvaluationTests(bool legacy, bool fallback) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.FormatSql, "false"); configuration.SetProperty(Environment.LinqToHqlLegacyPreEvaluation, LegacyPreEvaluation.ToString()); configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString()); @@ -323,7 +321,7 @@ public void CanSelectRandomDouble() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1)); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(1)); if (!LegacyPreEvaluation && IsFunctionSupported("random")) { @@ -380,7 +378,7 @@ public void CanSelectRandomInt() var randomValues = x.Select(o => o.r).Distinct().ToArray(); Assert.That( randomValues, - Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf()); + Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(int.MaxValue).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { @@ -436,7 +434,7 @@ public void CanSelectRandomIntWithMax() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf()); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.All.LessThan(10).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { @@ -492,7 +490,7 @@ public void CanSelectRandomIntWithMinMax() Assert.That(x, Has.Count.GreaterThan(0)); var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf()); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.All.LessThan(11).And.All.TypeOf()); if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) { diff --git a/src/NHibernate.Test/Linq/QueryCacheableTests.cs b/src/NHibernate.Test/Linq/QueryCacheableTests.cs index de4529091bf..779a4514f3a 100644 --- a/src/NHibernate.Test/Linq/QueryCacheableTests.cs +++ b/src/NHibernate.Test/Linq/QueryCacheableTests.cs @@ -10,11 +10,10 @@ namespace NHibernate.Test.Linq [TestFixture] public class QueryCacheableTests : LinqTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(cfg); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Linq/QueryFlushModeTests.cs b/src/NHibernate.Test/Linq/QueryFlushModeTests.cs index 796a76bf0e0..9eb896ab4e3 100644 --- a/src/NHibernate.Test/Linq/QueryFlushModeTests.cs +++ b/src/NHibernate.Test/Linq/QueryFlushModeTests.cs @@ -11,7 +11,6 @@ public class QueryFlushModeTests : LinqTestCase protected override void Configure(Configuration configuration) { configuration.SetProperty(Environment.GenerateStatistics, "true"); - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/Linq/QueryTimeoutTests.cs b/src/NHibernate.Test/Linq/QueryTimeoutTests.cs index bf6ba97bec5..5b74ae4bf20 100644 --- a/src/NHibernate.Test/Linq/QueryTimeoutTests.cs +++ b/src/NHibernate.Test/Linq/QueryTimeoutTests.cs @@ -22,7 +22,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchStrategy, typeof(TimeoutCatchingNonBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/Linq/WhereTests.cs b/src/NHibernate.Test/Linq/WhereTests.cs index 02dc58b34b7..9297d1e684d 100644 --- a/src/NHibernate.Test/Linq/WhereTests.cs +++ b/src/NHibernate.Test/Linq/WhereTests.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Linq.Expressions; using log4net.Core; +using NHibernate.Dialect; using NHibernate.Engine.Query; using NHibernate.Linq; using NHibernate.DomainModel.Northwind.Entities; @@ -55,6 +56,32 @@ public void WhereWithConstantExpression() Assert.That(query.Count, Is.EqualTo(1)); } + [Test(Description = "GH-3256")] + public void CanUseStringEnumInConditional() + { + var query = db.Users + .Where( + user => (user.Enum1 == EnumStoredAsString.Small + ? EnumStoredAsString.Small + : EnumStoredAsString.Large) == user.Enum1) + .Select(x => x.Enum1); + + Assert.That(query.Count(), Is.GreaterThan(0)); + } + + [Test(Description = "GH-3256")] + public void CanUseStringEnumInConditional2() + { + var query = db.Users + .Where( + user => (user.Enum1 == EnumStoredAsString.Small + ? user.Enum1 + : EnumStoredAsString.Large) == user.Enum1) + .Select(x => x.Enum1); + + Assert.That(query.Count(), Is.GreaterThan(0)); + } + [Test] public void FirstElementWithWhere() { @@ -645,6 +672,51 @@ where sheet.Users.Contains(user) Assert.That(query.Count, Is.EqualTo(2)); } + [Test] + public void TimesheetsWithEnumerableContainsOnSelect() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var value = (EnumStoredAsInt32) 1000; + var query = (from sheet in db.Timesheets + where sheet.Users.Select(x => x.NullableEnum2 ?? value).Contains(value) + select sheet).ToList(); + + Assert.That(query.Count, Is.EqualTo(1)); + } + + [Test] + public void TimesheetsWithProjectionInSubquery() + { + if (Dialect is MsSqlCeDialect) + Assert.Ignore("Dialect is not supported"); + + var query = (from sheet in db.Timesheets + where sheet.Users.Select(x => new { Id = x.Id, Name = x.Name }).Any(x => x.Id == 1) + select sheet).ToList(); + + Assert.That(query.Count, Is.EqualTo(2)); + } + + [Test] + public void ContainsSubqueryWithCoalesceStringEnumSelect() + { + if (Dialect is MsSqlCeDialect || Dialect is SQLiteDialect) + Assert.Ignore("Dialect is not supported"); + + var results = + db.Timesheets.Where( + o => + o.Users + .Where(u => u.Id != 0.MappedAs(NHibernateUtil.Int32)) + .Select(u => u.Name == u.Name ? u.Enum1 : u.NullableEnum1.Value) + .Contains(EnumStoredAsString.Small)) + .ToList(); + + Assert.That(results.Count, Is.EqualTo(1)); + } + [Test] public void SearchOnObjectTypeWithExtensionMethod() { diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/AllPropertiesRegistrationTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/AllPropertiesRegistrationTests.cs index 11f66934fa3..8b1c2d2a269 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/AllPropertiesRegistrationTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/AllPropertiesRegistrationTests.cs @@ -188,6 +188,20 @@ public void WhenMapPropertiesInTheBaseJumpedClassUsingMemberNameThenMapInInherit Assert.That(hbmClass.Properties.Select(p => p.Access).All(a => a.StartsWith("field.")), Is.True); } + [Test] + public void BackfieldAccessPropertyMapping() + { + var mapper = new ModelMapper(); + mapper.Class(mc => + { + mc.Id(x => x.Id, m => m.Access(Accessor.Backfield)); + }); + + HbmMapping mappings = mapper.CompileMappingForAllExplicitlyAddedEntities(); + HbmClass hbmClass = mappings.RootClasses[0]; + Assert.That(hbmClass.Id.access, Is.EqualTo("backfield")); + } + [Test] public void WhenMapBagWithWrongElementTypeThenThrows() { diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs index 39e9075ed3a..b408efda7e2 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/BasicMappingOfSimpleClass.cs @@ -33,7 +33,7 @@ public void AbstractClass() ca.Property(x => x.Something, map => map.Length(150)); }); var hbmMapping = mapper.CompileMappingFor(new[] { typeof(MyClass) }); - Assert.AreEqual(hbmMapping.RootClasses[0].@abstract, true); + Assert.AreEqual(true, hbmMapping.RootClasses[0].@abstract); } [Test] diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs index 2436fcb9890..e710636cab0 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/ComponentAsIdTests.cs @@ -41,7 +41,7 @@ public void CanSpecifyUnsavedValue() var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); - Assert.AreEqual(mapping.RootClasses[0].CompositeId.unsavedvalue, HbmUnsavedValueType.Any); + Assert.AreEqual(HbmUnsavedValueType.Any, mapping.RootClasses[0].CompositeId.unsavedvalue); } [Test] diff --git a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs index 6a49c66f20b..82031d04c08 100644 --- a/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs +++ b/src/NHibernate.Test/MappingByCode/ExplicitMappingTests/OptimisticLockModeTests.cs @@ -26,7 +26,7 @@ public void OptimisticLockModeTest() }); var mappings = mapper.CompileMappingForAllExplicitlyAddedEntities(); - Assert.AreEqual(mappings.RootClasses[0].optimisticlock, HbmOptimisticLockMode.Dirty); + Assert.AreEqual(HbmOptimisticLockMode.Dirty, mappings.RootClasses[0].optimisticlock); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs b/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs index 4a1a1b405ce..cf2eefe2018 100644 --- a/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs +++ b/src/NHibernate.Test/MappingByCode/IntegrationTests/NH3110/Fixture.cs @@ -20,7 +20,7 @@ public void CanSetPolymorphism() var mapping = mapper.CompileMappingForAllExplicitlyAddedEntities(); var entity = mapping.RootClasses[0]; - Assert.AreEqual(entity.polymorphism, HbmPolymorphismType.Explicit); + Assert.AreEqual(HbmPolymorphismType.Explicit, entity.polymorphism); } } } \ No newline at end of file diff --git a/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs b/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs index 81ed2e127b6..e9090db461d 100644 --- a/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs +++ b/src/NHibernate.Test/MappingByCode/ModelExplicitDeclarationsHolderMergeTest.cs @@ -343,7 +343,7 @@ public void MergeSplitDefinitions() source.AddAsPropertySplit(new SplitDefinition(typeof (MyClass), "foo", property)); destination.Merge(source); - Assert.That(destination.SplitDefinitions, Has.Count.EqualTo(1)); + Assert.That(destination.SplitDefinitions.Count(), Is.EqualTo(1)); } [Test] @@ -354,7 +354,7 @@ public void MergePersistentMembers() source.AddAsPersistentMember(property); destination.Merge(source); - Assert.That(destination.PersistentMembers, Has.Count.EqualTo(1)); + Assert.That(destination.PersistentMembers.Count(), Is.EqualTo(1)); } [Test] @@ -365,7 +365,7 @@ public void MergeProperties() source.AddAsProperty(property); destination.Merge(source); - Assert.That(destination.Properties, Has.Count.EqualTo(1)); + Assert.That(destination.Properties.Count(), Is.EqualTo(1)); } [Test] @@ -376,7 +376,7 @@ public void MergeDictionaries() source.AddAsMap(property); destination.Merge(source); - Assert.That(destination.Dictionaries, Has.Count.EqualTo(1)); + Assert.That(destination.Dictionaries.Count(), Is.EqualTo(1)); } [Test] @@ -387,7 +387,7 @@ public void MergeArrays() source.AddAsArray(property); destination.Merge(source); - Assert.That(destination.Arrays, Has.Count.EqualTo(1)); + Assert.That(destination.Arrays.Count(), Is.EqualTo(1)); } [Test] @@ -398,7 +398,7 @@ public void MergeLists() source.AddAsList(property); destination.Merge(source); - Assert.That(destination.Lists, Has.Count.EqualTo(1)); + Assert.That(destination.Lists.Count(), Is.EqualTo(1)); } [Test] @@ -409,7 +409,7 @@ public void MergeIdBags() source.AddAsIdBag(property); destination.Merge(source); - Assert.That(destination.IdBags, Has.Count.EqualTo(1)); + Assert.That(destination.IdBags.Count(), Is.EqualTo(1)); } [Test] @@ -420,7 +420,7 @@ public void MergeBags() source.AddAsBag(property); destination.Merge(source); - Assert.That(destination.Bags, Has.Count.EqualTo(1)); + Assert.That(destination.Bags.Count(), Is.EqualTo(1)); } [Test] @@ -431,7 +431,7 @@ public void MergeSets() source.AddAsSet(property); destination.Merge(source); - Assert.That(destination.Sets, Has.Count.EqualTo(1)); + Assert.That(destination.Sets.Count(), Is.EqualTo(1)); } [Test] @@ -442,7 +442,7 @@ public void MergeNaturalIds() source.AddAsNaturalId(property); destination.Merge(source); - Assert.That(destination.NaturalIds, Has.Count.EqualTo(1)); + Assert.That(destination.NaturalIds.Count(), Is.EqualTo(1)); } [Test] @@ -453,7 +453,7 @@ public void MergeVersionProperties() source.AddAsVersionProperty(property); destination.Merge(source); - Assert.That(destination.VersionProperties, Has.Count.EqualTo(1)); + Assert.That(destination.VersionProperties.Count(), Is.EqualTo(1)); } [Test] @@ -464,7 +464,7 @@ public void MergePoids() source.AddAsPoid(property); destination.Merge(source); - Assert.That(destination.Poids, Has.Count.EqualTo(1)); + Assert.That(destination.Poids.Count(), Is.EqualTo(1)); } [Test] @@ -475,7 +475,7 @@ public void MergeAny() source.AddAsAny(property); destination.Merge(source); - Assert.That(destination.Any, Has.Count.EqualTo(1)); + Assert.That(destination.Any.Count(), Is.EqualTo(1)); } [Test] @@ -486,7 +486,7 @@ public void MergeOneToManyRelations() source.AddAsOneToManyRelation(property); destination.Merge(source); - Assert.That(destination.OneToManyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.OneToManyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -497,7 +497,7 @@ public void MergeManyToAnyRelations() source.AddAsManyToAnyRelation(property); destination.Merge(source); - Assert.That(destination.ManyToAnyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ManyToAnyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -508,7 +508,7 @@ public void MergeManyToManyRelations() source.AddAsManyToManyItemRelation(property); destination.Merge(source); - Assert.That(destination.ItemManyToManyRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ItemManyToManyRelations.Count(), Is.EqualTo(1)); } [Test] @@ -519,7 +519,7 @@ public void MergeManyToOneRelations() source.AddAsManyToOneRelation(property); destination.Merge(source); - Assert.That(destination.ManyToOneRelations, Has.Count.EqualTo(1)); + Assert.That(destination.ManyToOneRelations.Count(), Is.EqualTo(1)); } [Test] @@ -530,7 +530,7 @@ public void MergeOneToOneRelations() source.AddAsOneToOneRelation(property); destination.Merge(source); - Assert.That(destination.OneToOneRelations, Has.Count.EqualTo(1)); + Assert.That(destination.OneToOneRelations.Count(), Is.EqualTo(1)); } [Test] @@ -541,7 +541,7 @@ public void MergeTablePerConcreteClassEntities() source.AddAsTablePerConcreteClassEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerConcreteClassEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerConcreteClassEntities.Count(), Is.EqualTo(1)); } [Test] @@ -552,7 +552,7 @@ public void MergeTablePerClassHierarchyEntities() source.AddAsTablePerClassHierarchyEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerClassHierarchyEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerClassHierarchyEntities.Count(), Is.EqualTo(1)); } [Test] @@ -563,7 +563,7 @@ public void MergeTablePerClassEntities() source.AddAsTablePerClassEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.TablePerClassEntities, Has.Count.EqualTo(1)); + Assert.That(destination.TablePerClassEntities.Count(), Is.EqualTo(1)); } [Test] @@ -574,7 +574,7 @@ public void MergeComponents() source.AddAsComponent(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.Components, Has.Count.EqualTo(1)); + Assert.That(destination.Components.Count(), Is.EqualTo(1)); } [Test] @@ -585,7 +585,7 @@ public void MergeRootEntities() source.AddAsRootEntity(typeof (MyClass)); destination.Merge(source); - Assert.That(destination.RootEntities, Has.Count.EqualTo(1)); + Assert.That(destination.RootEntities.Count(), Is.EqualTo(1)); } [Test] @@ -596,7 +596,7 @@ public void MergeDynamicComponents() source.AddAsDynamicComponent(property, typeof(MyClass)); destination.Merge(source); - Assert.That(destination.DynamicComponents, Has.Count.EqualTo(1)); + Assert.That(destination.DynamicComponents.Count(), Is.EqualTo(1)); Assert.That(destination.GetDynamicComponentTemplate(property), Is.EqualTo(typeof(MyClass))); } @@ -608,7 +608,7 @@ public void MergeComposedId() source.AddAsPartOfComposedId(property); destination.Merge(source); - Assert.That(destination.ComposedIds, Has.Count.EqualTo(1)); + Assert.That(destination.ComposedIds.Count(), Is.EqualTo(1)); } [Test] diff --git a/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs b/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs index 98b3ac55f28..41f3fe408b8 100644 --- a/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs +++ b/src/NHibernate.Test/MappingTest/NonReflectiveBinderFixture.cs @@ -53,7 +53,7 @@ public void MetaInheritance() { var ma = element.MetaAttributes; Assert.That(ma, Is.Not.Null); - Assert.That(element.GetMetaAttribute("global"), Is.Not.Null,"inherited attribute missing for prop {0}",element.Name); + Assert.That(element.GetMetaAttribute("global"), Is.Not.Null, $"inherited attribute missing for prop {element.Name}"); MetaAttribute metaAttribute2 = element.GetMetaAttribute("implements"); Assert.That(metaAttribute2, Is.Not.Null); Assert.That(element.GetMetaAttribute("globalnoinherit"), Is.Null); diff --git a/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs b/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs index fcd93d71595..32ddae24c52 100644 --- a/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs +++ b/src/NHibernate.Test/MultiTenancy/DatabaseStrategyNoDbSpecificFixture.cs @@ -32,7 +32,6 @@ protected override void Configure(Configuration configuration) x.MultiTenancyConnectionProvider(); }); configuration.Properties[Cfg.Environment.GenerateStatistics] = "true"; - base.Configure(configuration); } [Test] diff --git a/src/NHibernate.Test/NHAssert.cs b/src/NHibernate.Test/NHAssert.cs index 9eb04894774..72af6ab17ff 100644 --- a/src/NHibernate.Test/NHAssert.cs +++ b/src/NHibernate.Test/NHAssert.cs @@ -19,12 +19,12 @@ public static class NHAssert public static void HaveSerializableAttribute(System.Type clazz) { - HaveSerializableAttribute(clazz, null, null); + HaveSerializableAttribute(clazz, null); } - public static void HaveSerializableAttribute(System.Type clazz, string message, params object[] args) + public static void HaveSerializableAttribute(System.Type clazz, string message) { - Assert.That(clazz, Has.Attribute(), message, args); + Assert.That(clazz, Has.Attribute(), message); } public static void InheritedAreMarkedSerializable(System.Type clazz) @@ -54,15 +54,15 @@ public static void InheritedAreMarkedSerializable(System.Type clazz, string mess public static void IsSerializable(object obj) { - IsSerializable(obj, null, null); + IsSerializable(obj, null); } - public static void IsSerializable(object obj, string message, params object[] args) + public static void IsSerializable(object obj, string message) { #if NETFX - Assert.That(obj, Is.BinarySerializable, message, args); + Assert.That(obj, Is.BinarySerializable, message); #else - if (obj == null) throw new ArgumentNullException(nameof(args)); + if (obj == null) throw new ArgumentNullException(nameof(obj)); var formatter = new BinaryFormatter { SurrogateSelector = new SerializationHelper.SurrogateSelector() @@ -83,19 +83,19 @@ public static void IsSerializable(object obj, string message, params object[] ar } } - Assert.That(isSuccess, message, args); + Assert.That(isSuccess, message); #endif } public static void IsXmlSerializable(object obj) { - IsXmlSerializable(obj, null, null); + IsXmlSerializable(obj, null); } - public static void IsXmlSerializable(object obj, string message, params object[] args) + public static void IsXmlSerializable(object obj, string message) { #if NETFX - Assert.That(obj, Is.XmlSerializable, message, args); + Assert.That(obj, Is.XmlSerializable, message); #else if (obj == null) throw new ArgumentNullException(nameof(obj)); var isSuccess = false; @@ -116,7 +116,7 @@ public static void IsXmlSerializable(object obj, string message, params object[] } } - Assert.That(isSuccess, message, args); + Assert.That(isSuccess, message); #endif } diff --git a/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs b/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs index 76a18409c8e..3b0783d17c8 100644 --- a/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs +++ b/src/NHibernate.Test/NHSpecificTest/BugTestCase.cs @@ -15,7 +15,7 @@ public abstract class BugTestCase : TestCase protected sealed override string MappingsAssembly => throw new InvalidOperationException("BugTestCase does not support overriding mapping assembly."); - protected sealed override void AddMappings(Configuration configuration) + protected override void AddMappings(Configuration configuration) { var mappings = Mappings; if (mappings == null || mappings.Length == 0) @@ -26,4 +26,4 @@ protected sealed override void AddMappings(Configuration configuration) configuration.AddResource(type.Namespace + "." + file, type.Assembly); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs b/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs index 096419a336e..cfbc9094e22 100644 --- a/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/Dates/DateTimeOffsetQueryFixture.cs @@ -34,7 +34,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs index 66e1a522eb5..abf6cd31583 100644 --- a/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/EntityWithUserTypeCanHaveLinqGenerators/Fixture.cs @@ -21,7 +21,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.LinqToHqlGeneratorsRegistry(); } diff --git a/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs index 1d6d19132d1..f13d1ef9a4f 100644 --- a/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/FileStreamSql2008/Fixture.cs @@ -28,10 +28,10 @@ protected override bool AppliesTo(Dialect.Dialect dialect) return dialect is MsSql2008Dialect; } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { //Points to the database created with FileStream Filegroup. - cfg.Properties["connection.connection_string"] = + configuration.Properties["connection.connection_string"] = @"Data Source=localhost\SQLEXPRESS;Initial Catalog=FileStreamDB;Integrated Security=True;Pooling=False"; #region CREATE DATABASE example diff --git a/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs index 58c728c7028..a89c48bf64c 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH0000/Fixture.cs @@ -8,47 +8,45 @@ public class Fixture : BugTestCase { protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity {Name = "Bob"}; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); - var e2 = new Entity {Name = "Sally"}; - session.Save(e2); + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - transaction.Commit(); - } + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); + + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); - - transaction.Commit(); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); } [Test] public void YourTestName() { - using (var session = OpenSession()) - using (session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; - - Assert.That(result.ToList(), Has.Count.EqualTo(1)); - } + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + + transaction.Commit(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs index 2bc1953e095..a80b787db3d 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH0000/FixtureByCode.cs @@ -9,12 +9,12 @@ namespace NHibernate.Test.NHSpecificTest.GH0000 /// Fixture using 'by code' mappings /// /// - /// This fixture is identical to except the mapping is performed + /// This fixture is identical to except the mapping is performed /// by code in the GetMappings method, and does not require the Mappings.hbm.xml file. Use this approach /// if you prefer. /// [TestFixture] - public class ByCodeFixture : TestCaseMappingByCode + public class FixtureByCode : TestCaseMappingByCode { protected override HbmMapping GetMappings() { @@ -30,48 +30,46 @@ protected override HbmMapping GetMappings() protected override void OnSetUp() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var e1 = new Entity { Name = "Bob" }; - session.Save(e1); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); - var e2 = new Entity { Name = "Sally" }; - session.Save(e2); + var e2 = new Entity { Name = "Sally" }; + session.Save(e2); - transaction.Commit(); - } + transaction.Commit(); } protected override void OnTearDown() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHbernate ordering the deletes, but this will cause - // loading the entities in the session. - session.CreateQuery("delete from System.Object").ExecuteUpdate(); + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHbernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); - transaction.Commit(); - } + transaction.Commit(); } [Test] public void YourTestName() { - using (var session = OpenSession()) - using (var transaction = session.BeginTransaction()) - { - var result = from e in session.Query() - where e.Name == "Bob" - select e; + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session + .Query() + .Where(e => e.Name == "Bob"); + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); - Assert.That(result.ToList(), Has.Count.EqualTo(1)); - transaction.Commit(); - } + transaction.Commit(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH0829/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH0829/Fixture.cs new file mode 100644 index 00000000000..5726de6d4b2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH0829/Fixture.cs @@ -0,0 +1,61 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH0829 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Parent { Type = TestEnum.A | TestEnum.C }; + session.Save(e1); + + var e2 = new Child { Type = TestEnum.D, Parent = e1 }; + session.Save(e2); + + var e3 = new Child { Type = TestEnum.C, Parent = e1 }; + session.Save(e3); + + transaction.Commit(); + } + + [Test] + public void SelectClass() + { + using var session = OpenSession(); + + var resultFound = session.Query().Where(x => x.Type.HasFlag(TestEnum.A)).FirstOrDefault(); + + var resultNotFound = session.Query().Where(x => x.Type.HasFlag(TestEnum.D)).FirstOrDefault(); + + Assert.That(resultFound, Is.Not.Null); + Assert.That(resultNotFound, Is.Null); + } + + [Test] + public void SelectChildClassContainedInParent() + { + using var session = OpenSession(); + + var result = session.Query().Where(x => x.Parent.Type.HasFlag(x.Type)).FirstOrDefault(); + + Assert.That(result, Is.Not.Null); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + foreach (var entity in new[] { nameof(Child), nameof(Parent) }) + { + session.CreateQuery($"delete from {entity}").ExecuteUpdate(); + } + + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH0829/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH0829/Mappings.hbm.xml new file mode 100644 index 00000000000..7527c9d74c7 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH0829/Mappings.hbm.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH0829/Model.cs b/src/NHibernate.Test/NHSpecificTest/GH0829/Model.cs new file mode 100644 index 00000000000..92af512fddb --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH0829/Model.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH0829 +{ + public class Parent + { + public virtual Guid Id { get; set; } + + public virtual TestEnum Type { get; set; } + + public virtual IList Children { get; set; } = new List(); + } + + public class Child + { + public virtual Guid Id { get; set; } + + public virtual TestEnum Type { get; set; } + + public virtual Parent Parent { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH0829/TestEnum.cs b/src/NHibernate.Test/NHSpecificTest/GH0829/TestEnum.cs new file mode 100644 index 00000000000..5d3a919400e --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH0829/TestEnum.cs @@ -0,0 +1,13 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH0829 +{ + [Flags] + public enum TestEnum + { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + D = 1 << 3 + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs index 940b721a90b..64e4af85e3e 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1228/Fixture.cs @@ -2,132 +2,94 @@ namespace NHibernate.Test.NHSpecificTest.GH1228 { + [TestFixture] public class Fixture : BugTestCase { [Test] - public void TestOk() + public void TestThetaJoinOnAssociationInSubQuery() { - using (ISession s = OpenSession()) - { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatWorks = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - , ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatWorks.List(); - } - { - var queryThatWorks = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - , ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatWorks.List(); - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + using var s = OpenSession(); + var queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + , ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatWorks.List(); + + queryThatWorks = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + , ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatWorks.List(); } [Test] - public void TestWrongSql() + public void TestAnsiJoinOnAssociationInSubQuery() { - using (ISession s = OpenSession()) - { - using (ITransaction t = s.BeginTransaction()) - { - try - { - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN ROOT.Folder AS ROOT_Folder - WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN ROOT.Folders AS ROOT_Folder - WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - } - finally - { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + if (!TestDialect.SupportsCorrelatedColumnsInSubselectJoin) + Assert.Ignore("Dialect doesn't support this test case"); + + using var s = OpenSession(); + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN ROOT.Folder AS ROOT_Folder + WHERE ROOT_Folder.Shelf = inv AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN ROOT.Folders AS ROOT_Folder + WHERE ROOT_Folder = sheet.Folder AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. } [Test] - public void Test3() { - using (ISession s = OpenSession()) { - using (ITransaction t = s.BeginTransaction()) { - try { - { - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet - JOIN sheet.Folder AS folder - WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' - ) ) - AND ROOT.Id = 1"); - queryThatCreatesWrongSQL.List(); - // The only assertion here is that the generated SQL is valid and can be executed. - // Right now, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. - } - { - var queryThatCreatesWrongSQL = s.CreateQuery(@" - SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT - WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv - JOIN inv.Folders AS folder - WHERE folder = ROOT.Folder AND inv.Id = 1 - ) ) - AND ROOT.Name = 'SomeName'"); - queryThatCreatesWrongSQL.List(); - } - } - finally { - s.Delete("from Sheet"); - s.Delete("from Folder"); - s.Delete("from Shelf"); - t.Commit(); - } - } - } + public void TestOtherAnsiJoinOnAssociationInSubQuery() + { + using var s = OpenSession(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + var queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS sheet + JOIN sheet.Folder AS folder + WHERE folder.Shelf = ROOT AND sheet.Name = 'SomeName' + )) + AND ROOT.Id = 1"); + queryThatCreatesWrongSQL.List(); + + // The only assertion here is that the generated SQL is valid and can be executed. + // With the bug, the generated SQL is missing the JOIN inside the subselect (EXISTS) to Folder. + queryThatCreatesWrongSQL = s.CreateQuery( + @" + SELECT ROOT FROM NHibernate.Test.NHSpecificTest.GH1228.Sheet AS ROOT + WHERE (EXISTS (FROM NHibernate.Test.NHSpecificTest.GH1228.Shelf AS inv + JOIN inv.Folders AS folder + WHERE folder = ROOT.Folder AND inv.Id = 1 + )) + AND ROOT.Name = 'SomeName'"); + queryThatCreatesWrongSQL.List(); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs new file mode 100644 index 00000000000..55833dc3612 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Account.cs @@ -0,0 +1,9 @@ +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + public class Account + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual int OldAccountNumber { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs new file mode 100644 index 00000000000..da097ba72d8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Fixture.cs @@ -0,0 +1,49 @@ +using System; +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var account = new Account { Id = 1, Name = "Account_1", OldAccountNumber = 1 }; + var order = new HoldClose + { + Account = account, + CloseDate = new DateTime(2023, 1, 1) + }; + + session.Save(account); + session.Save(order); + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + transaction.Commit(); + } + + [Test] + [Explicit("Not fixed yet")] + public void ManyToOneTargettingAFormula() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var result = session.Query(); + + Assert.That(result.ToList(), Has.Count.EqualTo(1)); + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs b/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs new file mode 100644 index 00000000000..007c768dbb9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/HoldClose.cs @@ -0,0 +1,11 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH1313 +{ + public class HoldClose + { + public virtual int Id { get; set; } + public virtual Account Account { get; set; } + public virtual DateTime CloseDate { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml new file mode 100644 index 00000000000..04b321cd7f6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH1313/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + convert(int,substring([Oldaccountnumber],3,8)) + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs index 85a727f1ec6..e395d644b15 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1486/Fixture.cs @@ -12,7 +12,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(_interceptor); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs index 73c3be88fe8..a1be5480b81 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1496/Fixture.cs @@ -17,7 +17,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.AppendListeners(ListenerType.PostUpdate, new[] { _auditEventListener }); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs index 22267fb030c..b4d3d2ee329 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1547/Fixture.cs @@ -22,8 +22,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); DriverForSubstitutedCommand.DriverClass = driverClass; diff --git a/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs index 7d69c1c48bb..93e294a4067 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1730/Fixture.cs @@ -8,7 +8,7 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } protected override void OnTearDown() diff --git a/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs index 4b57f08e186..eb3afa36f6a 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1754/Fixture.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using NUnit.Framework; @@ -74,7 +75,7 @@ public void CanAddChildAfterFlush() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -92,7 +93,7 @@ public void CanAddChildAfterFlushWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(1)); Assert.That(parent.Children, Does.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -120,7 +121,7 @@ public void CanMergeWithTransientChild() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -141,7 +142,7 @@ public void CanMergeWithTransientChildWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(1)); // Merge should duplicate child and leave original instance un-associated with the session. Assert.That(parent.Children, Does.Not.Contain(child)); - Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(parent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } } @@ -167,7 +168,7 @@ public void CanChangeOwnershipOnFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -180,7 +181,7 @@ public void CanChangeOwnershipOnFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -203,7 +204,7 @@ public void CanChangeOwnershipOnFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -216,7 +217,7 @@ public void CanChangeOwnershipOnFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -242,7 +243,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -255,7 +256,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -278,7 +279,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -291,7 +292,7 @@ public void CanChangeOwnershipFromFlushedParentToNonFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -317,7 +318,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -330,7 +331,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushed() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -353,7 +354,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -366,7 +367,7 @@ public void CanChangeOwnershipFromNonFlushedParentToFlushedWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -392,7 +393,7 @@ public void CanChangeOwnershipOnNonFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -405,7 +406,7 @@ public void CanChangeOwnershipOnNonFlushedParents() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } @@ -428,7 +429,7 @@ public void CanChangeOwnershipOnNonFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0)); Assert.That(nextParent.Children, Has.Count.EqualTo(1)); Assert.That(nextParent.Children, Does.Contain(child)); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0)); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty)); } using (var session = OpenSession()) @@ -441,7 +442,7 @@ public void CanChangeOwnershipOnNonFlushedParentsWithoutTransaction() Assert.That(parent.Children, Has.Count.EqualTo(0), "Reloaded data"); Assert.That(nextParent.Children, Has.Count.EqualTo(1), "Reloaded data"); Assert.That(nextParent.Children, Does.Contain(child), "Reloaded data"); - Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(0), "Reloaded data"); + Assert.That(nextParent.Children.Single().Id, Is.Not.EqualTo(Guid.Empty), "Reloaded data"); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs similarity index 82% rename from src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs rename to src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs index 5dbe043ebfe..4edb09d5cb1 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1994/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH1994/ManyToManyFilteredFixture.cs @@ -1,6 +1,5 @@ using System.Linq; using NHibernate.Criterion; -using NHibernate.Dialect; using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; @@ -9,7 +8,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1994 { [TestFixture] - public class Fixture : BugTestCase + public class ManyToManyFilteredFixture : BugTestCase { protected override void OnSetUp() { @@ -30,14 +29,7 @@ protected override void OnTearDown() using (var session = OpenSession()) using (var transaction = session.BeginTransaction()) { - // The HQL delete does all the job inside the database without loading the entities, but it does - // not handle delete order for avoiding violating constraints if any. Use - // session.Delete("from System.Object"); - // instead if in need of having NHibernate ordering the deletes, but this will cause - // loading the entities in the session. - session.Delete("from System.Object"); - transaction.Commit(); } } @@ -59,9 +51,6 @@ public void TestUnfilteredLinqQuery() [Test] public void TestFilteredByWhereCollectionLinqQuery() { - if(Dialect is PostgreSQLDialect) - Assert.Ignore("Dialect doesn't support 0/1 to bool implicit cast"); - using (var s = OpenSession()) { var query = s.Query() @@ -139,5 +128,31 @@ public void TestQueryOverRestrictionWithClause() Assert.That(query[0].Documents.Count, Is.EqualTo(1), "filtered asset documents"); } } + + [Test] + public void LazyLoad() + { + using (var s = OpenSession()) + { + var asset = s.Query().First(); + Assert.That(asset.Documents.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(2)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } + + [Test] + public void LazyLoadFiltered() + { + using (var s = OpenSession()) + { + s.EnableFilter("deletedFilter").SetParameter("deletedParam", false); + + var asset = s.Query().First(); + Assert.That(asset.Documents.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsBag.Count, Is.EqualTo(1)); + Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1)); + } + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml index 449a4b8bc97..dba718ccde7 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/GH1994/Mappings.hbm.xml @@ -5,7 +5,7 @@ - + @@ -26,7 +26,7 @@ - + @@ -39,7 +39,7 @@ - + diff --git a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs index d32bf89a58a..a9c4270ade2 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepth0Fixture.cs @@ -15,7 +15,6 @@ public CircularReferenceFetchDepth0Fixture() : base(0) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", "0"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs index 68f834e4c02..f3fc4942303 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH2201/CircularReferenceFetchDepthFixture.cs @@ -17,7 +17,6 @@ public CircularReferenceFetchDepthFixture(int depth) : base(depth) protected override void Configure(Configuration configuration) { configuration.SetProperty("max_fetch_depth", _depth.ToString()); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs index 0138c8b8d27..f6a5d0536bb 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3113/FixtureByCode.cs @@ -32,8 +32,6 @@ protected override void Configure(Configuration configuration) var dialect = NHibernate.Dialect.Dialect.GetDialect(configuration.Properties); if (dialect is Oracle8iDialect) configuration.SetProperty(Environment.Dialect, typeof(Oracle9iDialect).FullName); - - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs index 18d56ce0b9a..0ef4c9e7029 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3176/FixtureByCode.cs @@ -49,7 +49,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseSecondLevelCache] = "true"; configuration.Properties[Environment.GenerateStatistics] = "true"; diff --git a/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs index 5702dec91da..1220858af09 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3198/FixtureByCode.cs @@ -22,7 +22,6 @@ protected override void Configure(Configuration configuration) { new TestEventListener() }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs index 9935fd79940..49c6953e049 100644 --- a/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs +++ b/src/NHibernate.Test/NHSpecificTest/GH3215/FixtureByCode.cs @@ -34,7 +34,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/NHSpecificTest/GH3263/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3263/Entity.cs new file mode 100644 index 00000000000..5ab30425878 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3263/Entity.cs @@ -0,0 +1,16 @@ +namespace NHibernate.Test.NHSpecificTest.GH3263 +{ + public class Employee + { + public virtual int EmployeeId { get; set; } + public virtual string Name { get; set; } + public virtual OptionalInfo OptionalInfo { get; set; } + } + + public class OptionalInfo + { + public virtual int EmployeeId { get; set; } + public virtual int Age { get; set; } + public virtual Employee Employee { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3263/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3263/Mappings.hbm.xml new file mode 100644 index 00000000000..371f348a5e9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3263/Mappings.hbm.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + Employee + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs new file mode 100644 index 00000000000..88ee2b54bc6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3263/ReuseFetchJoinFixture.cs @@ -0,0 +1,88 @@ +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3263 +{ + [TestFixture] + public class ReuseFetchJoinFixture : BugTestCase + { + protected override void OnSetUp() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var em = new Employee() { Name = "x", OptionalInfo = new OptionalInfo() }; + em.OptionalInfo.Employee = em; + s.Save(em); + t.Commit(); + } + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void ReuseJoinScalarSelect() + { + using var session = OpenSession(); + session.Query() + .Fetch(x => x.OptionalInfo) + .Where(x => x.OptionalInfo != null) + .Select(x => new { x.OptionalInfo.Age }) + .ToList(); + } + + [Test] + public void ReuseJoinScalarSelectHql() + { + using var session = OpenSession(); + session.CreateQuery( + "select x.OptionalInfo.Age " + + "from Employee x " + + "fetch x.OptionalInfo " + + "where x.OptionalInfo != null ").List(); + + } + + [Test] + public void ReuseJoinScalarSelectHql2() + { + using var session = OpenSession(); + session.CreateQuery( + "select x.OptionalInfo.Age " + + "from Employee x " + + "join fetch x.OptionalInfo o " + + "where o != null ").List(); + } + + [Test] + public void ReuseJoinScalarSelectHql3() + { + using var session = OpenSession(); + session.CreateQuery( + "select x.OptionalInfo.Age from Employee x " + + "join fetch x.OptionalInfo " + + "where x.OptionalInfo != null ").List(); + } + + [Test] + public void ReuseJoinEntityAndScalarSelect() + { + using var session = OpenSession(); + using var sqlLog = new SqlLogSpy(); + + var x = session.Query() + .Fetch(x => x.OptionalInfo) + .Where(x => x.OptionalInfo != null) + .Select(x => new { x, x.OptionalInfo.Age }) + .First(); + + Assert.That(sqlLog.Appender.GetEvents().Length, Is.EqualTo(1)); + Assert.That(NHibernateUtil.IsInitialized(x.x.OptionalInfo), Is.True); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3288/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3288/Entity.cs new file mode 100644 index 00000000000..9f85c760a14 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3288/Entity.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3288 +{ + class TopEntity + { + public virtual int Id { get; set; } + public virtual MiddleEntity MiddleEntity { get; set; } + } + class MiddleEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Components { get; set; } = new HashSet(); + } + + class Component + { + public virtual MiddleEntity MiddleEntity { get; set; } + public virtual int Value { get; set; } + + public override bool Equals(object obj) + { + return (obj as Component)?.MiddleEntity.Id == MiddleEntity.Id; + } + + public override int GetHashCode() + { + return MiddleEntity.Id.GetHashCode(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs new file mode 100644 index 00000000000..440c4f772bd --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3288/FetchAndCollectionJoinFixture.cs @@ -0,0 +1,47 @@ +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3288 +{ + [TestFixture] + public class FetchAndCollectionJoinFixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var middleEntity = new MiddleEntity(); + middleEntity.Components.Add(new Component { MiddleEntity = middleEntity, Value = 1 }); + var te = new TopEntity + { + MiddleEntity = middleEntity + }; + session.Save(middleEntity); + session.Save(te); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Delete("from System.Object"); + + transaction.Commit(); + } + + [Test] + public void ReuseEntityJoinWithCollectionJoin() + { + using var session = OpenSession(); + + var entities = session.Query() + .Fetch(e => e.MiddleEntity) + .Where(e => e.MiddleEntity.Components.Any(e => e.Value != 0)) + .ToList(); + Assert.That(entities.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3288/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3288/Mappings.hbm.xml new file mode 100644 index 00000000000..b9cd68ded6f --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3288/Mappings.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3289/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3289/FixtureByCode.cs new file mode 100644 index 00000000000..8bc20205c12 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3289/FixtureByCode.cs @@ -0,0 +1,100 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3289 +{ + [TestFixture] + public class ByCodeFixture : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Identity)); + rc.Property(x => x.Name); + rc.Component(x => x.Component); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.Identity)); + rc.Property(x => x.Name); + rc.Component(x => x.Component); + }); + mapper.JoinedSubclass(rc => + { + rc.Key(k => k.Column("Id")); + rc.Property(x => x.SomeProperty); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.Lazy(true); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new SubEntity { Name = "Jim" }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + if (Dialect.SupportsTemporaryTables) + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + else + session.Delete("from System.Object"); + + transaction.Commit(); + } + + [Test] + public void TestSubEntityInterfaceWithFetchIsPropertyInitialized() + { + using var session = OpenSession(); + var data = session.Query() + .Fetch(e => e.Component) + .ToList(); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + + [Test] + public void TestEntityInterfaceWithFetchIsPropertyInitialized() + { + using var session = OpenSession(); + var data = session.Query() + .Fetch(e => e.Component) + .ToList(); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + + [Test] + public void TestSubEntityWithFetchIsPropertyInitialized() + { + using var session = OpenSession(); + var data = session.Query() + .Fetch(e => e.Component) + .ToList(); + var result = NHibernateUtil.IsPropertyInitialized(data[0], "Component"); + + Assert.That(result, Is.True); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3289/Models.cs b/src/NHibernate.Test/NHSpecificTest/GH3289/Models.cs new file mode 100644 index 00000000000..ffbbeeb7bf7 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3289/Models.cs @@ -0,0 +1,37 @@ +namespace NHibernate.Test.NHSpecificTest.GH3289 +{ + public interface IEntity + { + int Id { get; set; } + string Name { get; set; } + Component Component { get; set; } + } + + public interface ISubEntity : IEntity + { + public bool SomeProperty { get; set; } + } + + public class Entity : IEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Component Component { get; set; } + } + public class OtherEntity : IEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual Component Component { get; set; } + } + + public class SubEntity : Entity, ISubEntity + { + public virtual bool SomeProperty { get; set; } + } + + public class Component + { + public virtual string Field { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3290/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3290/Entity.cs new file mode 100644 index 00000000000..0ef176af019 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3290/Entity.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3290 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Parents { get; set; } + public virtual ISet Children { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3290/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3290/Fixture.cs new file mode 100644 index 00000000000..f7c6fe8dbe0 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3290/Fixture.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3290 +{ + [TestFixture(true)] + [TestFixture(false)] + public class Fixture : TestCaseMappingByCode + { + private readonly bool _detectFetchLoops; + + public Fixture(bool detectFetchLoops) + { + _detectFetchLoops = detectFetchLoops; + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + + rc.Property( + x => x.Name + ); + + rc.Set( + x => x.Children, + v => + { + v.Table("EntityToEntity"); + v.Cascade(Mapping.ByCode.Cascade.None); + v.Inverse(true); + v.Key(x => + { + x.Column("ParentId"); + x.NotNullable(true); + }); + v.Lazy(CollectionLazy.Lazy); + v.Fetch(CollectionFetchMode.Join); + }, + h => h.ManyToMany(m => m.Column("ChildId")) + ); + + rc.Set( + x => x.Parents, + v => + { + v.Table("EntityToEntity"); + v.Cascade(Mapping.ByCode.Cascade.All); + + v.Key(x => + { + x.Column("ChildId"); + x.NotNullable(true); + }); + v.Lazy(CollectionLazy.Lazy); + v.Fetch(CollectionFetchMode.Join); + }, + h => h.ManyToMany(m => m.Column("ParentId")) + ); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + configuration.SetProperty(Environment.DetectFetchLoops, _detectFetchLoops ? "true" : "false"); + configuration.SetProperty(Environment.MaxFetchDepth, _detectFetchLoops ? "-1" : "2"); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var person = new Entity + { + Name = "pers", + Parents = new HashSet() + }; + session.Save(person); + var job = new Entity + { + Name = "job", + Children = new HashSet() + }; + session.Save(job); + + job.Children.Add(person); + person.Parents.Add(job); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateSQLQuery("delete from EntityToEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void QueryWithFetch() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + var all = session + .QueryOver() + .Fetch(SelectMode.Fetch, x => x.Children) + .Fetch(SelectMode.Fetch, x => x.Parents) + .TransformUsing(Transformers.DistinctRootEntity) + .List(); + + foreach (var entity in all) + { + var isPerson = entity.Name == "pers"; + if (isPerson) + Assert.That(entity.Parents, Has.Count.EqualTo(1), "Person's job not found or non-unique."); + else + Assert.That(entity.Children, Has.Count.EqualTo(1), "Job's employee not found or non-unique."); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3291/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3291/Fixture.cs new file mode 100644 index 00000000000..fa01d89b8f9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3291/Fixture.cs @@ -0,0 +1,67 @@ +using System; +using System.Linq; +using NHibernate.Criterion; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3291 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new Person { Name = "Bob", DateOfBirth = new DateTime(2009, 12, 23) }; + session.Save(e1); + + var e2 = new Person { Name = "Sally", DateOfBirth = new DateTime(2018, 9, 30) }; + session.Save(e2); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void Linq() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + DateTime? dateOfSearch = null; + + var result = ( + from person in session.Query() + where dateOfSearch == null || person.DateOfBirth > dateOfSearch + select person).ToList(); + + Assert.That(result, Has.Count.EqualTo(2)); + } + + [Test] + public void Hql() + { + using var session = OpenSession(); + using var _ = session.BeginTransaction(); + + DateTime? dateOfSearch = null; + + var result = + session.CreateQuery("from Person where :DateOfSearch is null OR DateOfBirth > :DateOfSearch") + .SetParameter("DateOfSearch", dateOfSearch, NHibernateUtil.DateTime) + .List(); + + Assert.That(result, Has.Count.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3291/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3291/Mappings.hbm.xml new file mode 100644 index 00000000000..1088c98b593 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3291/Mappings.hbm.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3291/Person.cs b/src/NHibernate.Test/NHSpecificTest/GH3291/Person.cs new file mode 100644 index 00000000000..d80efc2e094 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3291/Person.cs @@ -0,0 +1,11 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3291 +{ + class Person + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual DateTime? DateOfBirth { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs new file mode 100644 index 00000000000..d1d511eca59 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Fixture.cs @@ -0,0 +1,57 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3306NullableEntityCorrelatedSubquery +{ + [TestFixture] + public class Fixture : BugTestCase + { + private const string NAME_JOE = "Joe"; + private const string NAME_ALLEN = "Allen"; + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + var joe = new Customer { Name = NAME_JOE }; + session.Save(joe); + + var allen = new Customer { Name = NAME_ALLEN }; + session.Save(allen); + + var joeInvoice0 = new Invoice { Customer = joe, Number = 0 }; + session.Save(joeInvoice0); + + var allenInvoice1 = new Invoice { Customer = allen, Number = 1 }; + session.Save(allenInvoice1); + + tx.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var tx = session.BeginTransaction()) + { + session.Delete("from Invoice"); + session.Delete("from Customer"); + tx.Commit(); + } + } + + [Test] + public void NullableEntityInCorrelatedSubquery() + { + using (var s = OpenSession()) + { + var customers = s.Query().Where(c => c.Name == NAME_JOE); + var results = s.Query() + .Where(i => customers.Any(c => c.Invoices.Any(ci => ci.Customer == i.Customer))).ToList(); + + Assert.That(results.Count, Is.EqualTo(1)); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Mappings.hbm.xml new file mode 100644 index 00000000000..515584fe116 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Mappings.hbm.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Model.cs b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Model.cs new file mode 100644 index 00000000000..2c472579b00 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3306NullableEntityCorrelatedSubquery/Model.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3306NullableEntityCorrelatedSubquery +{ + public class Customer + { + public virtual int ID { get; protected set; } + public virtual ISet Invoices { get; set; } + public virtual string Name { get; set; } + } + + public class Invoice + { + public virtual int ID { get; protected set; } + public virtual Customer Customer { get; set; } + public virtual int Number { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs new file mode 100644 index 00000000000..3dba8b9c90b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Entity.cs @@ -0,0 +1,10 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + class Entity + { + public virtual long Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml new file mode 100644 index 00000000000..028a77a8a61 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/Mappings.hbm.xml @@ -0,0 +1,14 @@ + + + + + + + + + + select s.Id from Entity s where s.Name = :name + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs new file mode 100644 index 00000000000..c7c5f1967f0 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3311SqlQueryParam/SqlQueryParamTypeFixture.cs @@ -0,0 +1,50 @@ +using System.Data; +using NHibernate.Dialect; +using NHibernate.SqlTypes; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3311SqlQueryParam +{ + [TestFixture] + public class SqlQueryParamTypeFixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var e1 = new Entity {Name = "Bob"}; + session.Save(e1); + + var e2 = new Entity {Name = "Sally"}; + session.Save(e2); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return + //Dialects like SQL Server CE, Firebird don't distinguish AnsiString from String + (Dialect.GetTypeName(new SqlType(DbType.AnsiString)) != Dialect.GetTypeName(new SqlType(DbType.String)) + || Dialect is SQLiteDialect); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void AppliesParameterTypeFromQueryParam() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + s.GetNamedQuery("entityIdByName").SetParameter("name", "Bob").UniqueResult(); + Assert.That(log.GetWholeLog(), Does.Contain("Type: AnsiString")); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs new file mode 100644 index 00000000000..1e43d5554c1 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3317/Entity.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3317 +{ + public class Entity + { + public Guid Id { get; set; } + public string Name { get; set; } + public IList Entries { get; set; } = new List(); + } + + public class ComponentListEntry + { + public string DummyString { get; set; } + public EntityWithParent ComponentReference { get; set; } + } + + public class EntityWithParent + { + public Guid Id { get; set; } + public ParentEntity Parent { get; set; } + } + + public class ParentEntity + { + public Guid Id { get; set; } + public string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs new file mode 100644 index 00000000000..3847af79449 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3317/FixtureByCode.cs @@ -0,0 +1,112 @@ +using System; +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3317 +{ + [TestFixture(true)] + [TestFixture(false)] + public class ComponentsListFixture : TestCaseMappingByCode + { + private readonly bool _fetchJoinMapping; + private Guid _id; + + public ComponentsListFixture(bool fetchJoinMapping) + { + _fetchJoinMapping = fetchJoinMapping; + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var tr = session.BeginTransaction(); + var root = new Entity(); + root.Entries.Add(new ComponentListEntry { ComponentReference = null, DummyString = "one", }); + + session.Save(root); + tr.Commit(); + _id = root.Id; + } + + [Test] + public void LazyLoading() + { + using var newSession = OpenSession(); + var reloadedRoot = newSession.Get(_id); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + [Test] + public void QueryOverFetch() + { + using var newSession = OpenSession(); + var reloadedRoot = newSession.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Entries) + .Where(x => x.Id == _id) + .SingleOrDefault(); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + [Test] + public void LinqFetch() + { + using var newSession = OpenSession(); + var reloadedRoot = newSession.Query() + .Fetch(x => x.Entries) + .Where(x => x.Id == _id) + .SingleOrDefault(); + Assert.AreEqual(1, reloadedRoot.Entries.Count); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateSQLQuery("delete from Entries").ExecuteUpdate(); + session.Delete("from System.Object"); + transaction.Commit(); + } + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.Property(x => x.Name); + + rc.Bag( + x => x.Entries, + v => + { + if (_fetchJoinMapping) + v.Fetch(CollectionFetchMode.Join); + }, + h => h.Component(cmp => + { + cmp.Property(x => x.DummyString); + cmp.ManyToOne(x => x.ComponentReference); + })); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.ManyToOne(x => x.Parent, m => m.NotNullable(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, map => map.Generator(Generators.GuidComb)); + rc.Lazy(false); + rc.Property(x => x.Name); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs new file mode 100644 index 00000000000..e63e6c3819b --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Entity.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual int Version { get; set; } = -1; + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class EntityWithoutDeleteOrphan + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + } + + public class ChildEntity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs new file mode 100644 index 00000000000..a0ba4123dac --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Fixture.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3325 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void CanRemoveChildAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSave() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildAfterSaveAndExplicitFlush() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + parent.Children.Add(child); + session.Save(parent); + session.Flush(); + parent.Children.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + [Test] + public void CanRemoveChildFromUnwrappedCollectionAfterSaveAndExplicitFlush() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child" }; + var parentChildren = parent.Children; + parentChildren.Add(child); + session.Save(parent); + session.Flush(); + parentChildren.Remove(child); + var parentId = parent.Id; + var childId = child.Id; + t.Commit(); + + AssertParentIsChildless(parentId, childId); + } + + private void AssertParentIsChildless(Guid parentId, Guid childId) + { + using var session = OpenSession(); + + var parent = session.Get(parentId); + Assert.That(parent, Is.Not.Null); + Assert.That(parent.Children, Has.Count.EqualTo(0)); + + var child = session.Get(childId); + Assert.That(child, Is.Null); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml new file mode 100644 index 00000000000..712bf46fb1f --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3325/Mappings.hbm.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs new file mode 100644 index 00000000000..9f9b2bafce2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Entity.cs @@ -0,0 +1,17 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + public class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class ChildEntity + { + public virtual int Id { get; set; } + public virtual Entity Parent { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs new file mode 100644 index 00000000000..31efc796ed1 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Fixture.cs @@ -0,0 +1,68 @@ +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3327 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity { Name = "Parent" }; + var child = new ChildEntity { Name = "Child", Parent = parent }; + session.Save(parent); + session.Save(child); + t.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void NotIsCorrectlyHandled() + { + using var session = OpenSession(); + var q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That(q.List()[0], Is.EqualTo(1)); + + q = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND ROOT.Name = 'Parent' + )"); + Assert.That(q.List()[0], Is.EqualTo(0)); + } + + [Test] + public void NotNotExistsNegated() + { + using var log = new SqlLogSpy(); + using var session = OpenSession(); + var results = session.CreateQuery( + @"SELECT COUNT(ROOT.Id) + FROM Entity AS ROOT + WHERE NOT ( + NOT EXISTS (FROM ChildEntity AS CHILD WHERE CHILD.Parent = ROOT) + AND NOT ROOT.Name = 'Parent' + )").List(); + Assert.That(log.GetWholeLog(), Does.Not.Contains(" NOT ").IgnoreCase); + Assert.That(results.Count, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml new file mode 100644 index 00000000000..a6eee729fae --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3327/Mappings.hbm.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs new file mode 100644 index 00000000000..718d3ac3488 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Entity.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + public class Entity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } = new HashSet(); + public virtual OtherEntity OtherEntity { get; set; } + } + + public class ChildEntity + { + public virtual int Id { get; set; } + public virtual Entity Parent { get; set; } + public virtual string Name { get; set; } + public virtual GrandChildEntity Child { get; set; } + } + + public class GrandChildEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + public class OtherEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Entities { get; set; } = new HashSet(); + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs new file mode 100644 index 00000000000..8ebf4b1d29c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Fixture.cs @@ -0,0 +1,193 @@ +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3334 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [OneTimeSetUp] + public void OneTimeSetUp() + { + using var session = OpenSession(); + using var t = session.BeginTransaction(); + var parent = new Entity + { + Name = "Parent1", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "GrandChild" } } } + }; + session.Save(parent); + parent = new Entity + { + Name = "Parent2", + Children = { new ChildEntity { Name = "Child", Child = new GrandChildEntity { Name = "XGrandChild" } } } + }; + var other = new OtherEntity { Name = "ABC", Entities = {parent}}; + parent.OtherEntity = other; + session.Save(parent); + session.Save(other); + t.Commit(); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + session.CreateQuery("delete from ChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from GrandChildEntity").ExecuteUpdate(); + session.CreateQuery("delete from Entity").ExecuteUpdate(); + session.CreateQuery("delete from OtherEntity").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + return TestDialect.SupportsCorrelatedColumnsInSubselectJoin; + } + + public class TestCaseItem + { + public string Name { get; } + public string Hql { get; } + public int LineNumber { get; } + + public TestCaseItem(string name, string hql, [CallerLineNumber] int lineNumber = 0) + { + Name = name; + Hql = hql; + LineNumber = lineNumber; + } + + public override string ToString() => $"{LineNumber:0000}: {Name}"; + } + + public static IEnumerable GetNoExceptionOnExecuteQueryTestCases() + { + /* does not work because of inner join or theta join created for many-to-one + @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + WHERE + child.Child.Name like 'G%' + OR ROOT.OtherEntity.Name like 'A%' + )");*/ + + yield return new("Basic Elements case 1 FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("Basic Elements case 2 FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.OtherEntity) AS otherEntity + WHERE + otherEntity.Name like 'A%' + )"); + yield return new("HQL Elements FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + )"); + yield return new("HQL Elements FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ELEMENTS(ROOT.Children) AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + yield return new("HQL Entity FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'G%' + OR otherEntity.Name like 'G%' + ) + )"); + yield return new("HQL Entity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ChildEntity AS child + LEFT JOIN child.Child AS grandChild + LEFT JOIN ROOT.OtherEntity AS otherEntity + WHERE + child.Parent = ROOT + AND ( + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + ) + )"); + yield return new("FROM ROOT.Children FoundViaGrandChildG", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.Children AS child + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'G%' + )"); + yield return new("FROM ROOT.OtherEntity FoundViaOtherEntityA", @" + SELECT ROOT + FROM Entity AS ROOT + WHERE + EXISTS + (FROM ROOT.OtherEntity AS otherEntity + LEFT JOIN ChildEntity AS child ON child.Parent = ROOT + LEFT JOIN child.Child AS grandChild + WHERE + grandChild.Name like 'A%' + OR otherEntity.Name like 'A%' + )"); + } + + [Test, TestCaseSource(nameof(GetNoExceptionOnExecuteQueryTestCases))] + public void NoExceptionOnExecuteQuery(TestCaseItem testCase) + { + using var session = OpenSession(); + var q = session.CreateQuery(testCase.Hql); + Assert.That(q.List(), Has.Count.EqualTo(1)); + } + + protected override bool CheckDatabaseWasCleaned() + { + // same set of objects for each test + return true; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml new file mode 100644 index 00000000000..1f5bcdfe8e6 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3334/Mappings.hbm.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs new file mode 100644 index 00000000000..dc7800cc977 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3352/Entity.cs @@ -0,0 +1,31 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual EntityComponentMapped Parent { get; set; } + public virtual Component Component { get; set; } + } + + public class EntityNameMapped : Entity + { + } + + public class EntityParentMapped : Entity + { + } + + public class EntityComponentMapped : Entity + { + } + + public class Component + { + public string Field { get; set; } + + public EntityNameMapped Entity { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs new file mode 100644 index 00000000000..5b66027c963 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3352/FetchFromNotMappedBaseClassFixture.cs @@ -0,0 +1,163 @@ +using System.Linq; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Linq; +using NHibernate.Mapping.ByCode; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3352 +{ + [TestFixture] + public class FetchFromNotMappedBaseClassFixture : TestCaseMappingByCode + { + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name, m => m.Lazy(true)); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.ManyToOne(x => x.Parent, m => m.ForeignKey("none")); + }); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Component(x => x.Component); + }); + mapper.Component(rc => + { + rc.Property(x => x.Field); + rc.ManyToOne(x => x.Entity, m => m.ForeignKey("none")); + rc.Lazy(true); + }); + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var np = new EntityComponentMapped { Component = new Component { Field = "x" } }; + session.Save(np); + var e = new EntityParentMapped { Parent = np }; + session.Save(e); + var nameMapped = new EntityNameMapped { Name = "lazy" }; + session.Save(nameMapped); + np.Component.Entity = nameMapped; + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void CanFetchLazyComponentFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Component).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [Test] + public void CanFetchLazyComponentThenEntityFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query() + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanFetchLazyPropertyFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Name).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Name))); + Assert.That(result.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanThenFetchLazyComponentFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Parent).ThenFetch(x => x.Component).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0].Parent; + Assert.That(NHibernateUtil.IsInitialized(result), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + } + + [KnownBug("GH-3356")] + [Test(Description = "GH-3356" )] + public void FetchAfterSelect() + { + using var log = new SqlLogSpy(); + + using var s = OpenSession(); + var list = s.Query() + .Select(x => x.Parent) + .Fetch(x => x.Component) + .ThenFetch(x => x.Entity) + .ThenFetch(x => x.Name) + .ToList(); + Assert.That(list, Has.Count.EqualTo(1)); + var result = list[0]; + Assert.That(NHibernateUtil.IsPropertyInitialized(result, nameof(result.Component))); + Assert.That(result.Component.Field, Is.EqualTo("x")); + Assert.That(result.Component.Entity, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(result.Component.Entity), Is.True); + Assert.That(NHibernateUtil.IsPropertyInitialized(result.Component.Entity, nameof(result.Name)), Is.True); + Assert.That(result.Component.Entity.Name, Is.EqualTo("lazy")); + } + + [Test] + public void CanFetchEntityFromNotMappedBaseClass() + { + using var session = OpenSession(); + var list = session.Query().Fetch(x => x.Parent).ToList(); + + Assert.That(list, Has.Count.EqualTo(1)); + Assert.That(list[0].Parent, Is.Not.Null); + Assert.That(NHibernateUtil.IsInitialized(list[0].Parent)); + } + + [Test] + public void FetchNotMappedAssociationThrows() + { + using var session = OpenSession(); + var query = session.Query().Fetch(x => x.Parent); + + Assert.Throws(() => query.ToList()); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs new file mode 100644 index 00000000000..0bde7420b92 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Entity.cs @@ -0,0 +1,17 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + public class Entity1 + { + public virtual Guid Id { get; set; } + + public virtual Entity2 Child { get; set; } + } + public class Entity2 + { + public virtual Guid Id { get; set; } + + public virtual Entity1 Parent { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs new file mode 100644 index 00000000000..08f965eef1d --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Fixture.cs @@ -0,0 +1,63 @@ +using System; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3403OneToOne +{ + [TestFixture] + public class Fixture : BugTestCase + { + private Guid _id; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var entity = new Entity1 + { + Child = new Entity2() + }; + + entity.Child.Parent = entity; + + session.Save(entity); + transaction.Commit(); + _id = entity.Id; + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void OrphanDeleteForDetachedOneToOne() + { + Guid childId; + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var entity = session.Get(_id); + childId = entity.Child.Id; + session.Evict(entity.Child); + entity.Child = null; + + session.Flush(); + transaction.Commit(); + } + + using (var session = OpenSession()) + { + var entity = session.Get(_id); + Assert.That(entity, Is.Not.Null); + Assert.That(entity.Child, Is.Null, "Unexpected child on parent"); + + var child = session.Get(childId); + Assert.That(child , Is.Null, "Child is still in database"); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml new file mode 100644 index 00000000000..175d587c0ce --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3403OneToOne/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + Parent + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs new file mode 100644 index 00000000000..e208abe904c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3421/Entity.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + + private IDictionary _attributes; + public virtual IDictionary Attributes { + get { + if (_attributes == null) + _attributes = new Dictionary(); + return _attributes; + } + set => _attributes = value; + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs new file mode 100644 index 00000000000..4fe7cc67954 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3421/Fixture.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Cfg; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlCommand; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3421 +{ + [TestFixture] + public class ByCodeFixture : TestCaseMappingByCode + { + private SqlInterceptor _interceptor; + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Component(x => x.Attributes, new { + Sku = (string)null + }, dc => { + dc.Property(x => x.Sku); + }); + }); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + protected override void Configure(Configuration configuration) + { + base.Configure(configuration); + + _interceptor = new SqlInterceptor(); + + configuration.SetInterceptor(_interceptor); + } + + protected override void OnSetUp() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var e1 = new Entity { Name = "Bob" }; + session.Save(e1); + + var e2 = new Entity { Name = "Sally", Attributes = new Dictionary() { + { "Sku", "AAA" } + } }; + session.Save(e2); + + transaction.Commit(); + } + } + + protected override void OnTearDown() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + session.CreateQuery("delete from Entity").ExecuteUpdate(); + transaction.Commit(); + } + } + + [Test] + public void TestFlushDoesNotTriggerAnUpdate() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var foo = session.Query().ToList(); + + session.Flush(); + + var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList(); + + Assert.That(updateStatements, Has.Count.EqualTo(0)); + } + } + + public class SqlInterceptor : EmptyInterceptor + { + public IList SqlStatements = new List(); + + public override SqlString OnPrepareStatement(SqlString sql) + { + SqlStatements.Add(sql); + + return base.OnPrepareStatement(sql); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs new file mode 100644 index 00000000000..e72fe68c43c --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Entities.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual ISet Children { get; set; } + } + + class Child + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs new file mode 100644 index 00000000000..5c829ce5c2d --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Fixture.cs @@ -0,0 +1,49 @@ +using System.Collections.Generic; +using System.Linq; +using NHibernate.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3424 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var c1 = new Child { Name = "Rob" }; + session.Save(c1); + var e1 = new Entity { Name = "Bob", Children = new HashSet { c1 } }; + session.Save(e1); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete Child").ExecuteUpdate(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + [Test] + public void QueryingAfterFutureThenClear() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + var futureBob = session.Query().Where(e => e.Name == "Bob").ToFutureValue(q => q.FirstOrDefault()); + var bob = futureBob.Value; + Assert.That(bob, Is.Not.Null); + session.Clear(); + + var allQuery = session.Query(); + Assert.That(() => allQuery.ToList(), Has.Count.EqualTo(1)); + transaction.Commit(); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml new file mode 100644 index 00000000000..e692e287c11 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3424/Mappings.hbm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs new file mode 100644 index 00000000000..3a325ed9ba8 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Entities.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + class EntityA + { + public virtual Guid Id { get; set; } + public virtual ISet Children { get; set; } + } + class EntityB + { + public virtual Guid Id { get; set; } + public virtual EntityA Parent { get; set; } + } + class EntityC + { + public virtual Guid Id { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs new file mode 100644 index 00000000000..e51af1211d9 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Fixture.cs @@ -0,0 +1,20 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3465 +{ + [TestFixture] + public class Fixture : BugTestCase + { + [Test] + public void ThetaJoinSubQuery() + { + using (var session = OpenSession()) + using (session.BeginTransaction()) + { + var query = session.CreateQuery("select e.Id from EntityA e where exists (from e.Children b, EntityC c)"); + Assert.DoesNotThrow(() => query.List()); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml new file mode 100644 index 00000000000..b89c139fa29 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3465/Mappings.hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs b/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs new file mode 100644 index 00000000000..d00828d29f2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Entities.cs @@ -0,0 +1,30 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + public interface IPayment + { + public Guid Id { get; set; } + public decimal Amount { get; set; } + } + + public class CreditCardPayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + public virtual string CreditCardType { get; set; } + } + + public class CashPayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + } + + public class ChequePayment : IPayment + { + public virtual Guid Id { get; set; } + public virtual decimal Amount { get; set; } + public virtual string Bank { get; set; } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs new file mode 100644 index 00000000000..65c7b8a6e19 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Fixture.cs @@ -0,0 +1,75 @@ +using System.Linq; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.GH3474 +{ + [TestFixture] + public class Fixture : BugTestCase + { + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + var e1 = new CreditCardPayment { CreditCardType = "Visa", Amount = 50 }; + session.Save(e1); + + var e2 = new ChequePayment { Bank = "CA", Amount = 32 }; + session.Save(e2); + + var e3 = new CashPayment { Amount = 18.5m }; + session.Save(e3); + + transaction.Commit(); + } + + protected override void OnTearDown() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + + // The HQL delete does all the job inside the database without loading the entities, but it does + // not handle delete order for avoiding violating constraints if any. Use + // session.Delete("from System.Object"); + // instead if in need of having NHibernate ordering the deletes, but this will cause + // loading the entities in the session. + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + protected override bool AppliesTo(Dialect.Dialect dialect) + { + // Polymorphic updates require support of temp tables. + return Dialect.SupportsTemporaryTables; + } + + [Test] + public void PolymorphicUpdateShouldNotCommit() + { + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + var payment = session.Query().First(); + payment.Amount = 100; + session.Flush(); + + session.CreateQuery("update ChequePayment set Amount = 64").ExecuteUpdate(); + + transaction.Rollback(); + } + + using (var session = OpenSession()) + using (var transaction = session.BeginTransaction()) + { + IPayment payment = session.Query().First(); + Assert.That(payment.Amount, Is.EqualTo(50m)); + + payment = session.Query().First(); + Assert.That(payment.Amount, Is.EqualTo(32m)); + + transaction.Commit(); + } + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml new file mode 100644 index 00000000000..6ea3fc8c2b2 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3474/Mappings.hbm.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs new file mode 100644 index 00000000000..0326e557526 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/Entity.cs @@ -0,0 +1,54 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + public class Entity + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + public virtual char FirstChar { get; set; } + public virtual CharEnum CharacterEnum { get; set; } = CharEnum.SimpleChar; + public virtual Uri UriProperty { get; set; } + + public virtual byte ByteProperty { get; set; } + public virtual decimal DecimalProperty { get; set; } + public virtual double DoubleProperty { get; set; } + public virtual float FloatProperty { get; set; } + public virtual short ShortProperty { get; set; } + public virtual int IntProperty { get; set; } + public virtual long LongProperty { get; set; } + public virtual sbyte SByteProperty { get; set; } + public virtual ushort UShortProperty { get; set; } + public virtual uint UIntProperty { get; set; } + public virtual ulong ULongProperty { get; set; } + + public virtual DateTime DateTimeProperty { get; set; } = StaticDateProperty; + public virtual DateTime DateProperty { get; set; } = StaticDateProperty; + public virtual DateTimeOffset DateTimeOffsetProperty { get; set; } = StaticDateProperty; + public virtual DateTime TimeProperty { get; set; } = StaticDateProperty; + + public virtual Guid GuidProperty { get; set; } = Guid.Empty; + + public const string NameWithSingleQuote = "'; drop table Entity; --"; + public const string NameWithEscapedSingleQuote = @"\'; drop table Entity; --"; + + // Do not switch to property, the feature of referencing static fields in HQL does not work with properties. + public static string ArbitraryStringValue; + + public const char QuoteInitial = '\''; + public const char BackslashInitial = '\\'; + + public static readonly Uri UriWithSingleQuote = new("https://somewhere/?sql='; drop table Entity; --"); + public static readonly Uri UriWithEscapedSingleQuote = new(@"https://somewhere/?sql=\'; drop table Entity; --"); + + public static readonly DateTime StaticDateProperty = DateTime.Today; + public static readonly DateTimeOffset StaticDateTimeOffsetProperty = DateTimeOffset.Now; + } + + public enum CharEnum + { + SimpleChar = 'A', + SingleQuote = '\'', + Backslash = '\\' + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs new file mode 100644 index 00000000000..235fad90b75 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/FixtureByCode.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using NHibernate.Cfg.MappingSchema; +using NHibernate.Mapping.ByCode; +using NHibernate.SqlTypes; +using NHibernate.Type; +using NUnit.Framework; +using NUnit.Framework.Internal; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + [TestFixture] + public class FixtureByCode : TestCaseMappingByCode + { + + private readonly HashSet _unsupportedProperties = new(); + + protected override HbmMapping GetMappings() + { + var mapper = new ModelMapper(); + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Property(x => x.Name); + rc.Property(x => x.FirstChar); + rc.Property(x => x.CharacterEnum, m => m.Type>()); + rc.Property(x => x.UriProperty); + + rc.Property(x => x.ByteProperty); + rc.Property(x => x.DecimalProperty); + rc.Property(x => x.DoubleProperty); + rc.Property(x => x.FloatProperty); + rc.Property(x => x.ShortProperty); + rc.Property(x => x.IntProperty); + rc.Property(x => x.LongProperty); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.SByte)) + rc.Property(x => x.SByteProperty); + else + _unsupportedProperties.Add(nameof(Entity.SByteProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt16)) + rc.Property(x => x.UShortProperty); + else + _unsupportedProperties.Add(nameof(Entity.UShortProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt32)) + rc.Property(x => x.UIntProperty); + else + _unsupportedProperties.Add(nameof(Entity.UIntProperty)); + + if (TestDialect.SupportsSqlType(SqlTypeFactory.UInt64)) + rc.Property(x => x.ULongProperty); + else + _unsupportedProperties.Add(nameof(Entity.ULongProperty)); + + rc.Property(x => x.DateTimeProperty); + rc.Property(x => x.DateProperty, m => m.Type(NHibernateUtil.Date)); + if (TestDialect.SupportsSqlType(SqlTypeFactory.DateTimeOffSet)) + rc.Property(x => x.DateTimeOffsetProperty); + else + _unsupportedProperties.Add(nameof(Entity.DateTimeOffsetProperty)); + rc.Property(x => x.TimeProperty, m => m.Type(NHibernateUtil.Time)); + + rc.Property(x => x.GuidProperty); + }); + + mapper.Class(rc => + { + rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb)); + rc.Discriminator(x => x.Column("StringDiscriminator")); + rc.Property(x => x.Name); + rc.Abstract(true); + }); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithSingleQuote)); + mapper.Subclass(rc => rc.DiscriminatorValue(Entity.NameWithEscapedSingleQuote)); + + mapper.Import(); + + return mapper.CompileMappingForAllExplicitlyAddedEntities(); + } + + private CultureInfo _backupCulture; + private CultureInfo _backupUICulture; + + protected override void OnSetUp() + { + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.Save( + new Entity + { + Name = Entity.NameWithSingleQuote, + FirstChar = Entity.QuoteInitial, + CharacterEnum = CharEnum.SingleQuote, + UriProperty = Entity.UriWithSingleQuote + }); + session.Save( + new Entity + { + Name = Entity.NameWithEscapedSingleQuote, + FirstChar = Entity.BackslashInitial, + CharacterEnum = CharEnum.Backslash, + UriProperty = Entity.UriWithEscapedSingleQuote + }); + + transaction.Commit(); + + _backupCulture = CultureInfo.CurrentCulture; + _backupUICulture = CultureInfo.CurrentUICulture; + } + + protected override void OnTearDown() + { + if (_backupCulture != null) + { + CultureInfo.CurrentCulture = _backupCulture; + CultureInfo.CurrentUICulture = _backupUICulture; + } + + using var session = OpenSession(); + using var transaction = session.BeginTransaction(); + session.CreateQuery("delete from System.Object").ExecuteUpdate(); + + transaction.Commit(); + } + + private static readonly string[] StringInjectionsProperties = + { + nameof(Entity.NameWithSingleQuote), nameof(Entity.NameWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(StringInjectionsProperties))] + public void SqlInjectionInStrings(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.Name = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with name {propertyName}"); + } + + private static readonly string[] SpecialNames = + { + "\0; drop table Entity; --", + "\b; drop table Entity; --", + "\n; drop table Entity; --", + "\r; drop table Entity; --", + "\t; drop table Entity; --", + "\x1A; drop table Entity; --", + "\"; drop table Entity; --", + "\\; drop table Entity; --" + }; + + [TestCaseSource(nameof(SpecialNames))] + public void StringsWithSpecialCharacters(string name) + { + // We may not even be able to insert the entity. + var wasInserted = false; + try + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var e = new Entity { Name = name }; + s.Save(e); + t.Commit(); + + wasInserted = true; + } + catch (Exception e) + { + Assert.Warn($"The entity insertion failed with message {e}"); + } + + try + { + using var session = OpenSession(); + Entity.ArbitraryStringValue = name; + var list = session.CreateQuery($"from Entity e where e.Name = Entity.{nameof(Entity.ArbitraryStringValue)}").List(); + if (wasInserted && list.Count != 1) + Assert.Warn($"Unable to find entity with name {nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception e) + { + Assert.Warn($"The query has failed with message {e}"); + } + + // Check the db is not wrecked. + if (wasInserted) + { + using var session = OpenSession(); + var list = session + .CreateQuery("from Entity e where e.Name = :name") + .SetString("name", name) + .List(); + Assert.That(list, Has.Count.EqualTo(1)); + } + else + { + using var session = OpenSession(); + var all = session.CreateQuery("from Entity e").List(); + Assert.That(all, Has.Count.GreaterThan(0)); + } + } + + [Test] + public void SqlInjectionInStringDiscriminator() + { + using var session = OpenSession(); + + session.Save(new Subclass1 { Name = "Subclass1" }); + session.Save(new Subclass2 { Name = "Subclass2" }); + + // ObjectToSQLString is used for generating the inserts. + Assert.That(session.Flush, Throws.Nothing, "Unable to flush the subclasses"); + + foreach (var entityName in new[] { nameof(Subclass1), nameof(Subclass2) }) + { + var query = session.CreateQuery($"from {entityName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing, $"Unable to list entities of {entityName}"); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find the {entityName} entity"); + } + } + + private static readonly string[] CharInjectionsProperties = + { + nameof(Entity.QuoteInitial), nameof(Entity.BackslashInitial) + }; + + [TestCaseSource(nameof(CharInjectionsProperties))] + public void SqlInjectionInChar(string propertyName) + { + using var session = OpenSession(); + var query = session.CreateQuery($"from Entity e where e.FirstChar = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Is.Not.Null.And.Count.EqualTo(1), $"Unable to find entity with initial {propertyName}"); + } + + private static readonly string[] CharEnumInjections = + { + nameof(CharEnum.SingleQuote), nameof(CharEnum.Backslash) + }; + + [TestCaseSource(nameof(CharEnumInjections))] + public void SqlInjectionWithCharEnum(string enumName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.CharacterEnum = CharEnum.{enumName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with CharacterEnum {enumName}"); + } + + private static readonly string[] UriInjections = + { + nameof(Entity.UriWithSingleQuote), nameof(Entity.UriWithEscapedSingleQuote) + }; + + [TestCaseSource(nameof(UriInjections))] + public void SqlInjectionWithUri(string propertyName) + { + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.UriProperty = Entity.{propertyName}"); + IList list = null; + Assert.That(() => list = query.List(), Throws.Nothing); + Assert.That(list, Has.Count.EqualTo(1), $"Unable to find entity with UriProperty {propertyName}"); + } + + private static readonly string[] NumericalTypesInjections = + { + nameof(Entity.ByteProperty), + nameof(Entity.DecimalProperty), + nameof(Entity.DoubleProperty), + nameof(Entity.FloatProperty), + nameof(Entity.ShortProperty), + nameof(Entity.IntProperty), + nameof(Entity.LongProperty), + nameof(Entity.SByteProperty), + nameof(Entity.UShortProperty), + nameof(Entity.UIntProperty), + nameof(Entity.ULongProperty) + }; + + [TestCaseSource(nameof(NumericalTypesInjections))] + public void SqlInjectionInNumericalType(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + Entity.ArbitraryStringValue = "0; drop table Entity; --"; + using (var session = OpenSession()) + { + IQuery query; + // Defining that query is invalid and should throw. + try + { + query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{nameof(Entity.ArbitraryStringValue)}"); + } + catch (Exception ex) + { + // All good. + Assert.Pass($"The wicked query creation has been rejected, as it should: {ex}"); + // Needed for the compiler who does not know "Pass" always throw. + return; + } + + // The query definition has been accepted, run it. + try + { + query.List(); + } + catch (Exception ex) + { + // Expecting no exception at that point, but the test is to check if the injection succeeded. + Assert.Warn($"The wicked query execution has failed: {ex}"); + } + } + + // Check if we can still query Entity. If it succeeds, at least it means the injection failed. + using (var session = OpenSession()) + { + IList list = null; + Assert.That(() => list = session.CreateQuery("from Entity e").List(), Throws.Nothing); + Assert.That(list, Has.Count.GreaterThan(0)); + } + } + + private static readonly string[] DateTypesInjections = + { + nameof(Entity.DateTimeProperty), + nameof(Entity.DateProperty), + nameof(Entity.DateTimeOffsetProperty), + nameof(Entity.TimeProperty) + }; + + [TestCaseSource(nameof(DateTypesInjections))] + public void SqlInjectionWithDatetime(string propertyName) + { + Assume.That(_unsupportedProperties, Does.Not.Contains((object) propertyName), $"The {propertyName} property is unsupported by the dialect"); + + var wickedCulture = new CultureInfo("en-US"); + if (propertyName == nameof(Entity.TimeProperty)) + wickedCulture.DateTimeFormat.ShortTimePattern = "HH:mm:ss\\'\"; drop table Entity; --\""; + else + wickedCulture.DateTimeFormat.ShortDatePattern = "yyyy-MM-ddTHH:mm:ss\\'\"; drop table Entity; --\""; + CultureInfo.CurrentCulture = wickedCulture; + CultureInfo.CurrentUICulture = wickedCulture; + + using var session = OpenSession(); + + var staticPropertyName = propertyName == nameof(Entity.DateTimeOffsetProperty) ? + nameof(Entity.StaticDateTimeOffsetProperty) : nameof(Entity.StaticDateProperty); + var query = session.CreateQuery($"from Entity e where e.{propertyName} = Entity.{staticPropertyName}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(() => list = query.List(), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + + private static readonly string[] GuidInjections = + { + Entity.NameWithSingleQuote, Entity.NameWithEscapedSingleQuote + }; + + [TestCaseSource(nameof(GuidInjections))] + public void SqlInjectionWithGuid(string injection) + { + Entity.ArbitraryStringValue = $"{Guid.NewGuid()}{injection}"; + using var session = OpenSession(); + + var query = session.CreateQuery($"from Entity e where e.GuidProperty = Entity.{nameof(Entity.ArbitraryStringValue)}"); + IList list = null; + Assume.That(() => list = query.List(), Throws.Nothing, + "The first execution of the query failed, the injection has likely failed"); + // Execute again to check the table is still here. + Assert.That(() => list = query.List(), Throws.Nothing, + "The second execution of the query failed although the first one did not: the injection has succeeded"); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs b/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs new file mode 100644 index 00000000000..cb5dca25868 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/GH3516/Hierarchy.cs @@ -0,0 +1,18 @@ +using System; + +namespace NHibernate.Test.NHSpecificTest.GH3516 +{ + public class BaseClass + { + public virtual Guid Id { get; set; } + public virtual string Name { get; set; } + } + + public class Subclass1 : BaseClass + { + } + + public class Subclass2 : BaseClass + { + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs b/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs index 5ec72b4aa9e..bbdf7c4add0 100644 --- a/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/Logs/LogsFixture.cs @@ -35,7 +35,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs index 1dabda7a0ef..7294b508928 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1001/Fixture.cs @@ -10,7 +10,7 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } private int employeeId; diff --git a/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs index ae2d5b7f395..5327df58c05 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1098/FilterParameterOrderFixture.cs @@ -226,7 +226,7 @@ public void QueryMapElements() var a = query.UniqueResult(); - Assert.AreEqual(a.C[1], "Text1"); + Assert.AreEqual("Text1", a.C[1]); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs index 75b8e5d8765..f14cb381461 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1101/Fixture.cs @@ -11,8 +11,7 @@ public class Fixture : BugTestCase protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs index 092b7f9ead5..dfc95472917 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1144/Fixture.cs @@ -10,12 +10,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1144 [TestFixture] public class Fixture : BugTestCase { - private Configuration configuration; - protected override void Configure(Configuration configuration) { - this.configuration = configuration; - this.configuration.Properties[Environment.BatchSize] = "10"; + configuration.Properties[Environment.BatchSize] = "10"; } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs index dc8e2d841a1..0a5ee99fbb8 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1230/Fixture.cs @@ -7,9 +7,9 @@ namespace NHibernate.Test.NHSpecificTest.NH1230 [TestFixture,Ignore("TODO(Dario)This test demostrate the need of eliminate the 'bool' on pre-insert eventlisteners.")] public class Fixture : BugTestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetListener(ListenerType.PreInsert, new PreSaveDoVeto()); + configuration.SetListener(ListenerType.PreInsert, new PreSaveDoVeto()); } /// diff --git a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs index 04479bee70f..670feb9c0c3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1253/Fixture.cs @@ -74,7 +74,7 @@ public void MultiQuerySingleInList() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (var tx = s.BeginTransaction()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs index c0bcf309e9d..5a2b8c4e6cb 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1284/Fixture.cs @@ -2,35 +2,37 @@ namespace NHibernate.Test.NHSpecificTest.NH1284 { - [TestFixture, Ignore("Not supported yet.")] + [TestFixture] public class Fixture : BugTestCase { + protected override void OnTearDown() + { + using var s = OpenSession(); + using var tx = s.BeginTransaction(); + s.Delete("from Person"); + tx.Commit(); + } + [Test] public void EmptyValueTypeComponent() { Person jimmy; - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) { - Person p = new Person("Jimmy Hendrix"); + var p = new Person("Jimmy Hendrix"); s.Save(p); tx.Commit(); } - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) + using (var s = OpenSession()) + using (var tx = s.BeginTransaction()) { - jimmy = (Person)s.Get(typeof(Person), "Jimmy Hendrix"); + jimmy = s.Get("Jimmy Hendrix"); tx.Commit(); } - Assert.IsFalse(jimmy.Address.HasValue); - using (ISession s = OpenSession()) - using (ITransaction tx = s.BeginTransaction()) - { - s.Delete("from Person"); - tx.Commit(); - } + Assert.That(jimmy.Address, Is.Null); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml index 6b9e124d1c6..214bf7fb496 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH1284/Mappings.hbm.xml @@ -15,4 +15,4 @@ - \ No newline at end of file + diff --git a/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs index 0bad20e6fc7..5a321fe4ce0 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1394/Fixture.cs @@ -94,9 +94,9 @@ public void CanOrderBySubqueryProjection() // Oracle order NULL Last (ASC) nullRelationOffSet = 0; } - Assert.AreEqual(list[nullRelationOffSet].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet + 1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet + 2].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet + 1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet + 2].Name); } } } @@ -122,9 +122,9 @@ public void CanOrderBySubqueryProjectionDesc() // Oracle order NULL First (DESC) nullRelationOffSet = 2; } - Assert.AreEqual(list[nullRelationOffSet+2].Name, "Tim"); - Assert.AreEqual(list[nullRelationOffSet+1].Name, "Joe"); - Assert.AreEqual(list[nullRelationOffSet].Name, "Sally"); + Assert.AreEqual("Tim", list[nullRelationOffSet+2].Name); + Assert.AreEqual("Joe", list[nullRelationOffSet+1].Name); + Assert.AreEqual("Sally", list[nullRelationOffSet].Name); } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs index aa30ea8509b..590e5d740d7 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1413/PagingTest.cs @@ -28,7 +28,7 @@ public void Bug() ICriteria icriteria = criteria.GetExecutableCriteria(session); icriteria.SetFirstResult(0); icriteria.SetMaxResults(2); - Assert.That(2, Is.EqualTo(icriteria.List().Count)); + Assert.That(icriteria.List().Count, Is.EqualTo(2)); } using (ISession session = OpenSession()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs index d82d0ceae14..4f83381cce8 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1452/Fixture.cs @@ -9,7 +9,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs index 28f81cea773..9563b583fef 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1553/MsSQL/SnapshotIsolationUpdateConflictTest.cs @@ -182,7 +182,6 @@ protected override void OnTearDown() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.SqlExceptionConverter, typeof (SQLUpdateConflictToStaleStateExceptionConverter).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs index c2171e57609..fd3d0460e06 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1612/NativeSqlCollectionLoaderFixture.cs @@ -12,7 +12,6 @@ public class NativeSqlCollectionLoaderFixture : BugTestCase protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.UseQueryCache, WithQueryCache.ToString()); } @@ -232,7 +231,7 @@ private void Save(TArea area) where TArea : Area [Test] public void NativeUpdateQueryWithoutResults() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -247,7 +246,7 @@ public void NativeUpdateQueryWithoutResults() [Test] public void NativeScalarQueryWithoutResults() { - Assume.That(Dialect, Is.InstanceOf(), "This does not apply to {0}", Dialect); + Assume.That(Dialect, Is.InstanceOf(), $"This does not apply to {Dialect}"); Assume.That(WithQueryCache, Is.False, "This test does not use a cacheable query."); using (ISession session = OpenSession()) { @@ -266,7 +265,7 @@ public void NativeScalarQueryWithUndefinedResultset() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { @@ -289,7 +288,7 @@ public void NativeScalarQueryWithDefinedResultset() { if (!(Dialect is MsSql2000Dialect)) { - Assert.Ignore("This does not apply to {0}", Dialect); + Assert.Ignore($"This does not apply to {Dialect}"); } using (ISession session = OpenSession()) { diff --git a/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs index 5e0a028dc7a..9f5ad5e4bd5 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1679/Fixture.cs @@ -52,7 +52,7 @@ public void TestAction(System.Action action) action.Invoke(criteria); IList l = criteria.GetExecutableCriteria(session).List(); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs index 1673fde4fb4..aa1fa121ea9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1688/Fixture.cs @@ -61,7 +61,7 @@ public void TestAction(System.Action action) action.Invoke(criteria); IList l = criteria.GetExecutableCriteria(session).List(); - Assert.AreNotEqual(l, null); + Assert.AreNotEqual(null, l); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs index 2d832cb4149..f6fe534150f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1821/Fixture.cs @@ -30,13 +30,9 @@ from Entity Regex whitespaces = new Regex(@"\s+", RegexOptions.IgnoreCase | RegexOptions.Multiline | RegexOptions.Compiled); - Assert.AreEqual( - string.Compare( - whitespaces.Replace(sql, " ").Trim(), - whitespaces.Replace(renderedSql, " ").Trim(), - true - ), - 0 + Assert.That( + whitespaces.Replace(renderedSql, " ").Trim(), + Is.EqualTo(whitespaces.Replace(sql, " ").Trim()).IgnoreCase ); } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs index 88eac03b442..321b1c25833 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1849/Fixture.cs @@ -29,8 +29,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - // Ugly hack. _OrignalDialectIsMsSql2005Dialect = Regex.IsMatch(configuration.GetProperty("dialect"), "MsSql200(5|8)Dialect"); @@ -53,4 +51,4 @@ public void ExecutesCustomSqlFunctionContains() Assert.AreEqual(1, plan.SqlStrings.Length); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs b/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs index eb9a41f560b..e4a534f7f0e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1859/SampleTest.cs @@ -33,7 +33,7 @@ public void NativeQueryWithTwoComments() IQuery qry = session.CreateSQLQuery("select /* first comment */ o.* /* second comment*/ from domainclass o") .AddEntity("o", typeof (DomainClass)); var res = qry.List(); - Assert.AreEqual(res[0].Id, 1); + Assert.AreEqual(1, res[0].Id); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs b/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs index 6f6804197b0..1174e67fe79 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1882/TestCollectionInitializingDuringFlush.cs @@ -18,7 +18,6 @@ protected override void Configure(Configuration configuration) { listener }; - base.Configure(configuration); } protected override HbmMapping GetMappings() diff --git a/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs index 7b1ac3f7be7..d294510bce9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1989/Fixture.cs @@ -19,7 +19,6 @@ protected override bool AppliesTo(ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs index 83bb483dda8..a9b616424bd 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2043/Fixture.cs @@ -19,7 +19,6 @@ public override string GetEntityName(object entity) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetInterceptor(new Namer()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs index 54ed1c463ea..169cd406adb 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2055/Fixture.cs @@ -16,12 +16,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) return (dialect is Dialect.MsSql2000Dialect); } - protected override void Configure(Configuration configuration) - { - base.Configure(configuration); - cfg = configuration; - } - [Test] public void CanCreateAndDropSchema() { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs index 6871ca6e2dd..ce746a5b383 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2092/Fixture.cs @@ -27,7 +27,7 @@ public void ConstrainedLazyLoadedOneToOneUsingCastleProxy() Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.False); - Assert.That("Person1", Is.EqualTo(employee.Person.Name)); + Assert.That(employee.Person.Name, Is.EqualTo("Person1")); Assert.That(NHibernateUtil.IsInitialized(employee.Person), Is.True); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs index fefdf3254d3..5c303be7b17 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2093/Fixture.cs @@ -76,7 +76,7 @@ public void CanUseFieldInterceptingProxyAsHQLArgument() .SetEntity("p", person) .List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); } } finally diff --git a/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml index 64151c2d8bc..d5e799d7c91 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2113/Mappings.hbm.xml @@ -15,7 +15,7 @@ - + diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs b/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs index d3c4702ac69..2b9ea9bfd4f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Entity.cs @@ -86,6 +86,7 @@ public override int GetHashCode() private int _id_Doc; private int _id_base; public virtual IList RefferedDetails { get; set; } = new List(); + public virtual IList RefferedDetailsManyToMany { get; set; } = new List(); public int Id_Doc { diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs index 13d9922c9d2..a216a4d2357 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Fixture.cs @@ -14,8 +14,10 @@ protected override void OnSetUp() { var doc = new Document {Id_Base = 1, Id_Doc = 2}; session.Save(doc); - session.Save(new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}); + var detail = new DocumentDetailDocument {Id_Base = 1, Id_Doc = 2, Id_Item = 1, ReferencedDocument = doc}; + session.Save(detail); + doc.RefferedDetailsManyToMany.Add(detail); transaction.Commit(); } } @@ -42,6 +44,14 @@ public void LinqFetch() } } + [Test(Description = "GH-3239")] + public void LinqFetchManyToMany() + { + using var session = OpenSession(); + var result = session.Query().Fetch(x => x.RefferedDetailsManyToMany).First(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public void QueryOverFetch() { @@ -52,6 +62,14 @@ public void QueryOverFetch() } } + [Test(Description = "GH-3239")] + public void QueryOverFetchManyToMany() + { + using var session = OpenSession(); + var result = session.QueryOver().Fetch(SelectMode.Fetch, x => x.RefferedDetailsManyToMany).SingleOrDefault(); + Assert.That(result.RefferedDetailsManyToMany, Has.Count.EqualTo(1)); + } + [Test] public void LazyLoad() { @@ -62,5 +80,13 @@ public void LazyLoad() Assert.That(result.RefferedDetails.Count, Is.EqualTo(1)); } } + + [Test] + public void LazyLoadManyToMany() + { + using var session = OpenSession(); + var result = session.Query().First(); + Assert.That(result.RefferedDetailsManyToMany.Count, Is.EqualTo(1)); + } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml index b6b056c2f80..d04459f0265 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2174/Mappings.hbm.xml @@ -42,5 +42,18 @@ + + + + + + + + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs index b8441edf39a..235afc084b3 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2195/SQLiteMultiCriteriaTest.cs @@ -91,7 +91,7 @@ public void MultiCriteriaQueriesWithIntsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying IntData using (ISession session = this.OpenSession()) @@ -120,7 +120,7 @@ public void MultiCriteriaQueriesWithStringsShouldExecuteCorrectly() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); // Test querying StringData using (ISession session = this.OpenSession()) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs index d214b5655f6..ddb45bbf22e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2302/Fixture.cs @@ -1,4 +1,5 @@ using System.Data; +using NHibernate.Cfg; using NHibernate.Dialect; using NHibernate.Driver; using NHibernate.Mapping; @@ -7,29 +8,29 @@ namespace NHibernate.Test.NHSpecificTest.NH2302 { - [TestFixture] - public class Fixture : BugTestCase - { - protected override void Configure(Cfg.Configuration configuration) + [TestFixture] + public class Fixture : BugTestCase + { + protected override void AddMappings(Configuration configuration) { + base.AddMappings(configuration); + foreach (var cls in configuration.ClassMappings) { foreach (var prop in cls.PropertyIterator) { foreach (var col in prop.ColumnIterator) { - if (col is Column) + if (col is Column column && column.SqlType == "nvarchar(max)") { - var column = col as Column; - if (column.SqlType == "nvarchar(max)") - column.SqlType = Dialect.GetLongestTypeName(DbType.String); + column.SqlType = Dialect.GetLongestTypeName(DbType.String); } } } } } - protected override void OnTearDown() + protected override void OnTearDown() { CleanUp(); diff --git a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs index b5f15a3194a..f9e9f032c9e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs @@ -13,7 +13,6 @@ public class Fixture : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty("linqtohql.generatorsregistry", "NHibernate.Test.NHSpecificTest.NH2318.ExtendedLinqtoHqlGeneratorsRegistry, NHibernate.Test"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs index 0d1a2b43f13..6de826d4dae 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2439/NH2439Fixture.cs @@ -11,7 +11,6 @@ public class NH2439Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.ShowSql, "true"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs index ac6114feb78..4e753234f00 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2554/Fixture.cs @@ -14,7 +14,6 @@ protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) protected override void Configure(NHibernate.Cfg.Configuration configuration) { configuration.SetProperty(NHibernate.Cfg.Environment.Hbm2ddlKeyWords, "keywords"); - base.Configure(configuration); } protected override void OnSetUp() diff --git a/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs index 967cbf8e953..b5c7581f87f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2583/AbstractMassTestingFixture.cs @@ -13,7 +13,6 @@ public abstract class AbstractMassTestingFixture : BugTestCase public const int BatchSize = 200; protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.DataBaseIntegration(x => x.BatchSize = BatchSize+5); List cacheSettings = new List(configuration.Properties.Keys.Where(x => x.Contains("cache"))); foreach (var cacheSetting in cacheSettings) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs b/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs index 19e7ae2a6d1..7918a27b16c 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2660And2661/Test.cs @@ -38,7 +38,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { // to be sure we are using the new drive - base.Configure(configuration); configuration.DataBaseIntegration(x=> x.Driver()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs index 56d685c8047..a69396a8fa9 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2700/Fixture.cs @@ -22,7 +22,7 @@ protected override void Configure(Cfg.Configuration configuration) { _originalDialect = Dialect; - cfg.SetProperty(Environment.Dialect, typeof(CustomDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomDialect).AssemblyQualifiedName); } public static string GetSql(ICriteria criteria) diff --git a/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs index 8280f1c3b8a..9ebc12e4f4e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2869/Fixture.cs @@ -12,7 +12,6 @@ public class Fixture : BugTestCase protected override void Configure(Configuration configuration) { configuration.LinqToHqlGeneratorsRegistry(); - base.Configure(configuration); } protected override void OnSetUp() @@ -55,4 +54,4 @@ public void CustomExtensionWithConstantArgumentShouldBeIncludedInHqlProjection() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs index cdff9247ad9..acf4c0fcd5f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2898/Fixture.cs @@ -11,7 +11,6 @@ public class Fixture : BugTestCase { protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(BinaryFormatterCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -121,4 +120,4 @@ public void SecondLevelCacheWithHqlQueries() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml index bb35dc0ba6a..95c5fdeec3d 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH2907/Mappings.hbm.xml @@ -12,11 +12,11 @@ - + - \ No newline at end of file + diff --git a/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs index 706eb379177..bc0f382f6a2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3004/Fixture.cs @@ -41,7 +41,7 @@ private static void RunTest(TestSqlClientDriver driver) unusedParam.ParameterName = driver.FormatNameForParameter("unused"); command.Parameters.Add(unusedParam); - Assert.AreEqual(command.Parameters.Count, 2); + Assert.AreEqual(2, command.Parameters.Count); SqlString sqlString = new SqlStringBuilder() .AddParameter() @@ -49,7 +49,7 @@ private static void RunTest(TestSqlClientDriver driver) driver.RemoveUnusedCommandParameters(command, sqlString); - Assert.AreEqual(command.Parameters.Count, 1); + Assert.AreEqual(1, command.Parameters.Count); Assert.AreEqual(command.Parameters[0], usedParam); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs index 0c6e98895a4..47e0171160f 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3023/DeadlockConnectionPoolIssueTest.cs @@ -113,7 +113,7 @@ public void ConnectionPoolCorruptionAfterDeadlock(bool distributed, bool dispose // // ? This shouldn't happen // - Assert.Fail("Surprising exception when trying to force a deadlock: {0}", x); + Assert.Fail($"Surprising exception when trying to force a deadlock: {x}"); } _log.WarnFormat("Initial session seemingly not deadlocked at attempt {0}", tryCount); @@ -243,11 +243,11 @@ public void ConnectionPoolCorruptionAfterDeadlock(bool distributed, bool dispose } } - Assert.Fail("{0}; {1} subsequent requests failed.", - missingDeadlock - ? "Deadlock not reported on initial request, and initial request failed" - : "Initial request failed", - subsequentFailedRequests); + Assert.Fail( + missingDeadlock + ? $"Deadlock not reported on initial request, and initial request failed; {subsequentFailedRequests} subsequent requests failed." + : $"Initial request failed; {subsequentFailedRequests} subsequent requests failed."); + } while (tryCount < 3); // // I'll change this to while(true) sometimes so I don't have to keep running the test diff --git a/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs index 92e2994f147..1fd18d43f67 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3058/SampleTest.cs @@ -8,8 +8,6 @@ public class SampleTest : BugTestCase { protected override void Configure(Cfg.Configuration configuration) { - base.Configure(configuration); - configuration.Properties.Add("current_session_context_class", "thread_static"); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs b/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs index c9d982b2a4f..739cf8d5ec2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3142/ChildrenTest.cs @@ -21,7 +21,6 @@ public ChildrenTest(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs index 219ef8ad1bd..7bcc5f836a2 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3202/Fixture.cs @@ -16,11 +16,11 @@ protected override void Configure(Configuration configuration) if (!(Dialect is MsSql2008Dialect)) Assert.Ignore("Test is for MS SQL Server dialect only (custom dialect)."); - if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)))) + if (!typeof(SqlClientDriver).IsAssignableFrom(ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)))) Assert.Ignore("Test is for MS SQL Server driver only (custom driver is used)."); - cfg.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(OffsetStartsAtOneTestDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(OffsetTestDriver).AssemblyQualifiedName); } private OffsetStartsAtOneTestDialect OffsetStartsAtOneTestDialect diff --git a/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs index 8da7a871fc1..ec5d6d8be27 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3426/Fixture.cs @@ -38,8 +38,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is SQLiteDialect) { var connStr = configuration.Properties[Environment.ConnectionString]; diff --git a/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs index 3625746d047..8e61e97ceea 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3489/Fixture.cs @@ -61,7 +61,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchSize, batchSize.ToString(CultureInfo.InvariantCulture)); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs index 45ca778c972..396a5ed3ba5 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3530/BatchFetchStyleFixture.cs @@ -24,7 +24,6 @@ public BatchFetchStyleFixture(BatchFetchStyle fetchStyle) protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.BatchFetchStyle, _fetchStyle.ToString()); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs index f617a69752f..c8021a7d7f6 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3848/Fixture.cs @@ -76,7 +76,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Cache(c => { c.UseQueryCache = true; diff --git a/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs index 1996d943be9..41562a8e13a 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3850/MainFixture.cs @@ -1430,12 +1430,12 @@ public void OverloadReflectionBluntPerfCompare() } swEnHlp.Stop(); - Assert.Pass(@"Blunt perf timings: -Direct reflection: {0} -Current impl, same overload: {1} -Current impl, other overload: {2} -EnumerableHelper.GetMethod(non generic overload): {3}", - swNoSameParamsCheck.Elapsed, swCurrentChoiceSameType.Elapsed, swCurrentChoice.Elapsed, swEnHlp.Elapsed); + Assert.Pass( + $@"Blunt perf timings: +Direct reflection: {swNoSameParamsCheck.Elapsed} +Current impl, same overload: {swCurrentChoiceSameType.Elapsed} +Current impl, other overload: {swCurrentChoice.Elapsed} +EnumerableHelper.GetMethod(non generic overload): {swEnHlp.Elapsed}"); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs index 396fd38a48a..84007aa39a1 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3912/ReusableBatcherFixture.cs @@ -36,7 +36,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Cfg.Environment.BatchStrategy, typeof(OracleDataClientBatchingBatcherFactory).AssemblyQualifiedName); } diff --git a/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs index 200e338cd15..0eca4c718e1 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH3952/Fixture.cs @@ -160,16 +160,14 @@ public void ReflectionBluntPerfCompare() } swEnHlp.Stop(); - Assert.Pass(@"Blunt perf timings: -Cached method: {0} -Cached method definition + make gen: {1} -Hazzik GetMethod: {5} -Hazzik GetMethodDefinition + make gen: {6} -ReflectHelper.GetMethod: {2} -ReflectHelper.GetMethodDefinition + make gen: {3} -EnumerableHelper.GetMethod(generic overload): {4}", - swCached.Elapsed, swCachedDef.Elapsed, swRefl.Elapsed, swReflDef.Elapsed, swEnHlp.Elapsed, - swRefl2.Elapsed, swRefl2Def.Elapsed); + Assert.Pass($@"Blunt perf timings: +Cached method: {swCached.Elapsed} +Cached method definition + make gen: {swCachedDef.Elapsed} +Hazzik GetMethod: {swRefl2.Elapsed} +Hazzik GetMethodDefinition + make gen: {swRefl2Def.Elapsed} +ReflectHelper.GetMethod: {swRefl.Elapsed} +ReflectHelper.GetMethodDefinition + make gen: {swReflDef.Elapsed} +EnumerableHelper.GetMethod(generic overload): {swEnHlp.Elapsed}"); } public static MethodInfo GetMethod2(Func func, T arg1) @@ -183,4 +181,4 @@ public static MethodInfo GetMethodDefinition2(Func func, return method.IsGenericMethod ? method.GetGenericMethodDefinition() : method; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs index 9cb011fc9b0..ac1ea430c36 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH4077/PostInsertFixture.cs @@ -61,7 +61,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostInsertEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs index ba2b9beb351..4a073046410 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH4077/PostUpdateFixture.cs @@ -55,7 +55,6 @@ protected override HbmMapping GetMappings() protected override void Configure(Configuration configuration) { - base.Configure(configuration); var existingListeners = (configuration.EventListeners.PostUpdateEventListeners ?? Array.Empty()).ToList(); // this evil listener uses the session to perform a few queries and causes an auto-flush to happen existingListeners.Add(new CausesAutoflushListener()); diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs index 7a77e8b2e04..b4496828089 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Device.cs @@ -6,6 +6,11 @@ namespace NHibernate.Test.NHSpecificTest.NH750 { public class Device { + private int _id; + private Device _template; + private IList _drives = new List(); + private IList _drivesNotIgnored = new List(); + public Device() : base() { } @@ -16,9 +21,13 @@ public Device(string manifacturer) _manifacturer = manifacturer; } - private int _id; + public virtual Device Template + { + get => _template; + set => _template = value; + } - public int Id + public virtual int Id { get { return _id; } set { _id = value; } @@ -26,18 +35,23 @@ public int Id private string _manifacturer; - public string Manifacturer + public virtual string Manifacturer { get { return _manifacturer; } set { _manifacturer = value; } } - private IList _drives = new List(); - public IList Drives + public virtual IList Drives { get { return _drives; } set { _drives = value; } } + + public virtual IList DrivesNotIgnored + { + get => _drivesNotIgnored; + set => _drivesNotIgnored = value; + } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs index b449dfb27ea..0e473bdf875 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Drive.cs @@ -16,7 +16,7 @@ public Drive(string classFullName) private int _id; - public int Id + public virtual int Id { get { return _id; } set { _id = value; } @@ -24,7 +24,7 @@ public int Id private string _classFullName; - public string ClassFullName + public virtual string ClassFullName { get { return _classFullName; } set { _classFullName = value; } @@ -44,4 +44,4 @@ public override int GetHashCode() return _classFullName.GetHashCode(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs deleted file mode 100644 index b766cd8b87e..00000000000 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Fixture.cs +++ /dev/null @@ -1,113 +0,0 @@ -using System; -using NHibernate.Cfg; -using NUnit.Framework; - -namespace NHibernate.Test.NHSpecificTest.NH750 -{ - [TestFixture] - public class Fixture : BugTestCase - { - protected override void OnTearDown() - { - using (ISession s = Sfi.OpenSession()) - { - s.Delete("from Device"); - s.Delete("from Drive"); - s.Flush(); - } - } - - protected override void Configure(Configuration configuration) - { - configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false"); - base.Configure(configuration); - } - - [Test] - public void DeviceOfDrive() - { - int[] dvSavedId = new int[2]; - Drive dr1 = new Drive("Drive 1"); - Drive dr2 = new Drive("Drive 2"); - Drive dr3 = new Drive("Drive 3"); - Device dv1 = new Device("Device 1"); - Device dv2 = new Device("Device 2"); - using (ISession s = Sfi.OpenSession()) - { - s.Save(dr1); - s.Save(dr2); - s.Save(dr3); - dvSavedId[0] = (int) s.Save(dv1); - dvSavedId[1] = (int) s.Save(dv2); - s.Flush(); - } - - dv1.Drives.Add(dr1); - dv1.Drives.Add(dr2); - dv2.Drives.Add(dr1); - dv2.Drives.Add(dr3); - using (ISession s = Sfi.OpenSession()) - { - dvSavedId[0] = (int) s.Save(dv1); - dvSavedId[1] = (int) s.Save(dv2); - s.Flush(); - } - dv1 = null; - dv2 = null; - using (ISession s = Sfi.OpenSession()) - { - s.Delete(dr3); - s.Flush(); - dv1 = (Device) s.Load(typeof(Device), dvSavedId[0]); - dv2 = (Device) s.Load(typeof(Device), dvSavedId[1]); - } - Assert.AreEqual(2, dv1.Drives.Count); - // Verify one is missing - Assert.AreEqual(1, dv2.Drives.Count); - // Verify dv1 unchanged - Assert.IsTrue(dv1.Drives.Contains(dr1)); - Assert.IsTrue(dv1.Drives.Contains(dr2)); - - // Verify dv2 - Assert.IsTrue(dv2.Drives.Contains(dr1)); - Assert.IsFalse(dv2.Drives.Contains(dr3)); - - //Make sure that flush didn't touch not-found="ignore" records for not modified collection - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = s.Get(dv2.Id); - s.Flush(); - t.Commit(); - } - - VerifyResult(expectedInCollection: 1, expectedInDb: 2, msg: "not modified collection"); - - //Many-to-many clears collection and recreates it so not-found ignore records are lost - using (var s = Sfi.OpenSession()) - using (var t = s.BeginTransaction()) - { - dv2 = s.Get(dv2.Id); - dv2.Drives.Add(dr2); - t.Commit(); - } - - VerifyResult(2, 2, msg: "modified collection"); - - void VerifyResult(int expectedInCollection, int expectedInDb, string msg) - { - using (var s = Sfi.OpenSession()) - { - var realCound = Convert.ToInt32( - s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") - .SetParameter("id", dv2.Id) - .UniqueResult()); - dv2 = s.Get(dv2.Id); - - Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); - Assert.That(realCound, Is.EqualTo(expectedInDb), msg); - } - } - } - } -} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs new file mode 100644 index 00000000000..dd923c1a1eb --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyFixture.cs @@ -0,0 +1,144 @@ +using System; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyFixture : BugTestCase + { + private int id2; + private readonly int _drivesCount; + private int _withTemplateId; + private int ValidDrivesCount => _drivesCount; + + public ManyToManyFixture(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.DrivesNotIgnored.Count >= _drivesCount) + return; + dv.DrivesNotIgnored.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public void QueryOverFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void QueryOverFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.CreateQuery("from Device d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.DrivesNotIgnored where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.DrivesNotIgnored), Is.True); + Assert.That(withTemplate.Template.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void LazyLoad() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + + var dv2 = s.Get(id2); + + NHibernateUtil.Initialize(dv2.DrivesNotIgnored); + Assert.That(NHibernateUtil.IsInitialized(dv2.DrivesNotIgnored), Is.True); + Assert.That(dv2.DrivesNotIgnored, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + // First query for Device, second for Drives collection + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(2)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs new file mode 100644 index 00000000000..3762342e932 --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyNotFoundIgnoreFixture.cs @@ -0,0 +1,208 @@ +using System; +using NHibernate.Criterion; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture(0)] + [TestFixture(1)] + [TestFixture(2)] + public class ManyToManyNotFoundIgnoreFixture : BugTestCase + { + private int id1; + private int id2; + private int _drive2Id; + private int _withTemplateId; + private readonly int _drivesCount; + private int ValidDrivesCount => _drivesCount == 0 ? 0 : _drivesCount - 1; + + public ManyToManyNotFoundIgnoreFixture(int drivesCount) + { + _drivesCount = drivesCount; + } + + protected override void OnSetUp() + { + Drive dr1 = new Drive("Drive 1"); + Drive dr2 = new Drive("Drive 2"); + Drive dr3 = new Drive("Drive 3"); + Device dv1 = new Device("Device 1"); + Device dv2 = new Device("Device 2"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv2 }; + + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + s.Save(dr1); + _drive2Id = (int)s.Save(dr2); + s.Save(dr3); + AddDrive(dv1, dr2); + AddDrive(dv1, dr1); + AddDrive(dv2, dr3); + AddDrive(dv2, dr1); + + id1 = (int) s.Save(dv1); + id2 = (int) s.Save(dv2); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr3); + t.Commit(); + } + + private void AddDrive(Device dv, Drive drive) + { + if(dv.Drives.Count >= _drivesCount) + return; + dv.Drives.Add(drive); + } + + protected override void OnTearDown() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + + s.CreateSQLQuery("delete from DriveOfDevice").ExecuteUpdate(); + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + + [Test] + public void DeviceOfDrive() + { + Device dv1; + Device dv2; + using (ISession s = Sfi.OpenSession()) + { + dv1 = (Device) s.Load(typeof(Device), id1); + dv2 = (Device) s.Load(typeof(Device), id2); + NHibernateUtil.Initialize(dv1.Drives); + NHibernateUtil.Initialize(dv2.Drives); + } + + Assert.That(dv1.Drives, Has.Count.EqualTo(_drivesCount).And.None.Null); + // Verify one is missing + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + + //Make sure that flush didn't touch not-found="ignore" records for not modified collection + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = s.Get(dv2.Id); + s.Flush(); + t.Commit(); + } + + VerifyResult(expectedInCollection: ValidDrivesCount, expectedInDb: _drivesCount, msg: "not modified collection"); + + // Many-to-many clears collection and recreates it so not-found ignore records are lost + // Note: It's not the case when no valid records are present, so loaded Drives collection is empty + // Just skip this check in this case: + if (_drivesCount < 2) + return; + + using (var s = Sfi.OpenSession()) + using (var t = s.BeginTransaction()) + { + dv2 = s.Get(dv2.Id); + dv2.Drives.Add(s.Load(_drive2Id)); + t.Commit(); + } + + VerifyResult(_drivesCount, _drivesCount, msg: "modified collection"); + + void VerifyResult(int expectedInCollection, int expectedInDb, string msg) + { + using (var s = Sfi.OpenSession()) + { + var realCound = Convert.ToInt32( + s.CreateSQLQuery("select count(*) from DriveOfDevice where DeviceId = :id ") + .SetParameter("id", dv2.Id) + .UniqueResult()); + dv2 = s.Get(dv2.Id); + + Assert.That(dv2.Drives.Count, Is.EqualTo(expectedInCollection), msg); + Assert.That(realCound, Is.EqualTo(expectedInDb), msg); + } + } + } + + [Test] + public void QueryOverFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Drives) + .Where(Restrictions.IdEq(id2)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void QueryOverFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.Template, x => x.Template.Drives) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity) + .SingleOrDefault(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var dv2 = s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True); + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void HqlFetch2() + { + using var log = new SqlLogSpy(); + using var s = OpenSession(); + var withTemplate = s.CreateQuery("from Device t left join fetch t.Template d left join fetch d.Drives where d.id = :id") + .SetResultTransformer(Transformers.DistinctRootEntity) + .SetParameter("id", id2) + .UniqueResult(); + + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template), Is.True); + Assert.That(NHibernateUtil.IsInitialized(withTemplate.Template.Drives), Is.True); + Assert.That(withTemplate.Template.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + + [Test] + public void LazyLoad() + { + using var s = OpenSession(); + + var dv2 = s.Get(id2); + using var log = new SqlLogSpy(); + + Assert.That(dv2.Drives, Has.Count.EqualTo(ValidDrivesCount).And.None.Null); + Assert.That(log.Appender.GetEvents().Length, Is.EqualTo(1)); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs new file mode 100644 index 00000000000..27ce2d3aaaf --- /dev/null +++ b/src/NHibernate.Test/NHSpecificTest/NH750/ManyToManyThrowsForNotFoundFixture.cs @@ -0,0 +1,98 @@ +using System.Linq; +using NHibernate.Criterion; +using NHibernate.Linq; +using NHibernate.Transform; +using NUnit.Framework; + +namespace NHibernate.Test.NHSpecificTest.NH750 +{ + [TestFixture] + public class ManyToManyThrowsForNotFoundFixture : BugTestCase + { + private int _id; + private int _withTemplateId; + + protected override void OnSetUp() + { + using var s = Sfi.OpenSession(); + using var t = s.BeginTransaction(); + Device dv = new Device("Device"); + Drive dr = new Drive("Drive"); + var withTemplate = new Device("Device With Device 2 template") { Template = dv }; + s.Save(dr); + dv.DrivesNotIgnored.Add(dr); + + _id = (int) s.Save(dv); + _withTemplateId = (int)s.Save(withTemplate); + s.Flush(); + + s.Clear(); + s.Delete(dr); + t.Commit(); + } + + protected override void OnTearDown() + { + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + s.Delete("from Device"); + s.Delete("from Drive"); + t.Commit(); + } + } + + [Test] + public void LazyLoad() + { + using var s = OpenSession(); + var device = s.Get(_id); + Assert.Throws(() => NHibernateUtil.Initialize(device.DrivesNotIgnored)); + } + + [Test] + public void QueryOverFetch() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored) + .Where(Restrictions.IdEq(_id)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.Throws(() => queryOver.SingleOrDefault()); + } + + [Test] + public void QueryOverFetch2() + { + using var s = OpenSession(); + var queryOver = s.QueryOver() + .Fetch(SelectMode.Fetch, x=> x.Template, x => x.Template.DrivesNotIgnored) + .Where(Restrictions.IdEq(_withTemplateId)) + .TransformUsing(Transformers.DistinctRootEntity); + Assert.Throws(() => queryOver.SingleOrDefault()); + } + + [Test] + public void LinqFetch() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.DrivesNotIgnored) + .Where(x => x.Id == _id); + Assert.Throws(() => NHibernateUtil.Initialize(query.SingleOrDefault())); + } + + [Test] + public void LinqFetch2() + { + using var s = OpenSession(); + var query = s.Query() + + .Fetch(x => x.Template) + .ThenFetchMany(x => x.DrivesNotIgnored) + .Where(x => x.Id == _withTemplateId); + Assert.Throws(() => NHibernateUtil.Initialize(query.SingleOrDefault())); + } + } +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml index 6a100d7926d..e2b3987d60e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml +++ b/src/NHibernate.Test/NHSpecificTest/NH750/Mappings.hbm.xml @@ -2,17 +2,21 @@ + default-access="field.camelcase-underscore"> - + + + + + + diff --git a/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs index 28c088902b6..657c0bb738e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH940/NH940Fixture.cs @@ -37,7 +37,7 @@ public void Bug() } catch (Exception e) { - Assert.Fail("Should have thrown MyException, thrown {0} instead", e); + Assert.Fail($"Should have thrown MyException, thrown {e} instead"); } } diff --git a/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs b/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs index 4bbcca81380..ac86449cde3 100644 --- a/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs +++ b/src/NHibernate.Test/NHSpecificTest/Properties/CompositePropertyRefTest.cs @@ -61,7 +61,7 @@ public void MappingOuterJoin() Assert.IsNull(p2.Address); Assert.IsNotNull(p.Address); var l = s.CreateQuery("from Person").List(); //pull address references for cache - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsTrue(l.Contains(p) && l.Contains(p2)); } } @@ -75,7 +75,7 @@ public void AddressBySequentialSelect() using (s.BeginTransaction()) { var l = s.CreateQuery("from Person p order by p.Name").List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); Assert.IsNull(l[0].Address); Assert.IsNotNull(l[1].Address); } @@ -90,7 +90,7 @@ public void AddressOuterJoin() using (s.BeginTransaction()) { var l = s.CreateQuery("from Person p left join fetch p.Address a order by a.Country").List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); if (l[0].Name.Equals("Max")) { Assert.IsNull(l[0].Address); @@ -135,11 +135,11 @@ public void AccountsOuterJoinVerifyInitialization() var l = s.CreateQuery("from Person p left join fetch p.Accounts a order by p.Name").List(); var p0 = l[0]; Assert.IsTrue(NHibernateUtil.IsInitialized(p0.Accounts)); - Assert.AreEqual(p0.Accounts.Count, 1); + Assert.AreEqual(1, p0.Accounts.Count); Assert.AreSame(p0.Accounts.First().User, p0); var p1 = l[1]; Assert.IsTrue(NHibernateUtil.IsInitialized(p1.Accounts)); - Assert.AreEqual(p1.Accounts.Count, 0); + Assert.AreEqual(0, p1.Accounts.Count); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs index 2a16a4578a1..c110eb370ba 100644 --- a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/Fixture.cs @@ -1,7 +1,6 @@ using System; using NHibernate.Proxy; using NUnit.Framework; -using System.Collections.Generic; namespace NHibernate.Test.NHSpecificTest.ProxyValidator { @@ -10,15 +9,6 @@ public class Fixture { private readonly IProxyValidator pv = new DynProxyTypeValidator(); - private void Validate(System.Type type) - { - ICollection errors = pv.ValidateType(type); - if (errors != null) - { - throw new InvalidProxyTypeException(errors); - } - } - public class ValidClass { private int privateField; @@ -64,12 +54,35 @@ protected int NonVirtualPrivateProperty #pragma warning restore 67 } + [Test] + public void ObjectIsValid() + { + var errors = pv.ValidateType(typeof(object)); + Assert.That(errors, Is.Null); + } + [Test] public void ValidClassTest() { - Validate(typeof(ValidClass)); + var errors = pv.ValidateType(typeof(ValidClass)); + Assert.That(errors, Is.Null); } + public class InvalidSealedToString : ValidClass + { + public sealed override string ToString() + { + return base.ToString(); + } + } + + [Test] + public void SealedObjectOverride() + { + var errors = pv.ValidateType(typeof(InvalidSealedToString)); + Assert.That(errors, Has.Count.EqualTo(1)); + } + public class InvalidPrivateConstructor : ValidClass { private InvalidPrivateConstructor() @@ -80,7 +93,8 @@ private InvalidPrivateConstructor() [Test] public void PrivateConstructor() { - Assert.Throws(() => Validate(typeof(InvalidPrivateConstructor))); + var errors = pv.ValidateType(typeof(InvalidPrivateConstructor)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidNonVirtualProperty : ValidClass @@ -95,7 +109,8 @@ public int NonVirtualProperty [Test] public void NonVirtualProperty() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } public class InvalidPublicField : ValidClass @@ -106,7 +121,8 @@ public class InvalidPublicField : ValidClass [Test] public void PublicField() { - Assert.Throws(() => Validate(typeof(InvalidPublicField))); + var errors = pv.ValidateType(typeof(InvalidPublicField)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidNonVirtualEvent : ValidClass @@ -119,7 +135,8 @@ public class InvalidNonVirtualEvent : ValidClass [Test] public void NonVirtualEvent() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualEvent))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualEvent)); + Assert.That(errors, Has.Count.EqualTo(2)); } public interface ValidInterface @@ -129,7 +146,8 @@ public interface ValidInterface [Test] public void Interface() { - Validate(typeof(ValidInterface)); + var errors = pv.ValidateType(typeof(ValidInterface)); + Assert.That(errors, Is.Null); } public class MultipleErrors @@ -153,15 +171,8 @@ public int NonVirtualProperty [Test] public void MultipleErrorsReported() { - try - { - Validate(typeof(MultipleErrors)); - Assert.Fail("Should have failed validation"); - } - catch (InvalidProxyTypeException e) - { - Assert.IsTrue(e.Errors.Count > 1); - } + var errors = pv.ValidateType(typeof(MultipleErrors)); + Assert.That(errors, Has.Count.GreaterThan(1)); } public class InvalidNonVirtualInternalProperty : ValidClass @@ -183,16 +194,18 @@ public class InvalidInternalField : ValidClass [Test] public void NonVirtualInternal() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualInternalProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualInternalProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } [Test] public void InternalField() { - Assert.Throws(() => Validate(typeof(InvalidInternalField))); + var errors = pv.ValidateType(typeof(InvalidInternalField)); + Assert.That(errors, Has.Count.EqualTo(1)); } - public class InvalidNonVirtualProtectedProperty : ValidClass + public class ValidNonVirtualProtectedProperty : ValidClass { protected int NonVirtualProperty { @@ -204,8 +217,8 @@ protected int NonVirtualProperty [Test] public void NonVirtualProtected() { - Validate(typeof(InvalidNonVirtualProtectedProperty)); - Assert.IsTrue(true, "Always should pass, protected members do not need to be virtual."); + var errors = pv.ValidateType(typeof(ValidNonVirtualProtectedProperty)); + Assert.That(errors, Is.Null); } public class InvalidNonVirtualProtectedInternalProperty : ValidClass @@ -220,7 +233,8 @@ protected internal int NonVirtualProperty [Test] public void NonVirtualProtectedInternal() { - Assert.Throws(() => Validate(typeof(InvalidNonVirtualProtectedInternalProperty))); + var errors = pv.ValidateType(typeof(InvalidNonVirtualProtectedInternalProperty)); + Assert.That(errors, Has.Count.EqualTo(2)); } interface INonVirtualPublicImplementsInterface @@ -239,7 +253,8 @@ public int NonVirtualMethodImplementsInterface [Test] public void VirtualPublicImplementsInterface() { - Assert.Throws(() => Validate(typeof(NonVirtualPublicImplementsInterface))); + var errors = pv.ValidateType(typeof(NonVirtualPublicImplementsInterface)); + Assert.That(errors, Has.Count.EqualTo(1)); } public class InvalidVirtualPrivateAutoProperty : ValidClass @@ -254,7 +269,8 @@ public virtual int NonVirtualSetterProperty [Test] public void PrivateSetterOnVirtualPropertyShouldThrows() { - Assert.Throws(() => Validate(typeof(InvalidVirtualPrivateAutoProperty))); + var errors = pv.ValidateType(typeof(InvalidVirtualPrivateAutoProperty)); + Assert.That(errors, Has.Count.EqualTo(1)); } } } diff --git a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs index 1a6fe621ccd..bb29e990bb2 100644 --- a/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs +++ b/src/NHibernate.Test/NHSpecificTest/ProxyValidator/ShouldBeProxiableTests.cs @@ -8,12 +8,27 @@ namespace NHibernate.Test.NHSpecificTest.ProxyValidator [TestFixture] public class ShouldBeProxiableTests { - private class MyClass: IDisposable + private class MyClass : IDisposable { public void Dispose() { } + + ~MyClass() + { + } + + // ReSharper disable once InconsistentNaming + // This is intentionally lower case + public virtual void finalize() + { + } + + public virtual void Finalize(int a) + { + } } + private class ProtectedNoVirtualProperty { protected int Aprop { get; set; } @@ -31,24 +46,154 @@ protected internal void AProtectedInternal() { } } [Test] - public void GetTypeNotBeProxiable() + public void ObjectToStringShouldBeProxiable() + { + var method = typeof(object).GetMethod(nameof(ToString)); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); + } + + [Test] + public void ObjectGetHashCodeShouldBeProxiable() + { + var method = typeof(object).GetMethod(nameof(GetHashCode)); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); + } + + [Test] + public void ObjectEqualsShouldBeProxiable() + { + var method = typeof(object).GetMethod(nameof(Equals), BindingFlags.Public | BindingFlags.Instance); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); + } + + [Test] + public void ObjectMemberwiseCloneShouldNotBeProxiable() + { + var method = typeof(object).GetMethod( + nameof(MemberwiseClone), + BindingFlags.Instance | BindingFlags.NonPublic); + + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); + } + + [Test] + public void ObjectGetTypeShouldNotBeProxiable() { var method = typeof(object).GetMethod("GetType"); - Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); } [Test] - public void DisposeNotBeProxiable() + public void MyClassDisposeNotBeProxiable() { var method = typeof(MyClass).GetMethod("Dispose"); - Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); + } + + [Test] + public void ObjectDestructorShouldNotBeProxiable() + { + var method = typeof(object).GetMethod( + "Finalize", + BindingFlags.NonPublic | BindingFlags.Instance); + + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); + } + + [Test] + public void MyClassDestructorShouldNotBeProxiable() + { + var method = typeof(MyClass).GetMethod( + "Finalize", + BindingFlags.NonPublic | BindingFlags.Instance, + null, + System.Type.EmptyTypes, + null); + + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.False); + Assert.That(method.IsProxiable(), Is.False); + }); + } + + [Test] + public void MyClassLowerCaseFinalizeShouldBeProxiable() + { + var method = typeof(MyClass).GetMethod( + "finalize", + BindingFlags.Public | BindingFlags.Instance, + null, + System.Type.EmptyTypes, + null); + + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); + } + + [Test] + public void MyClassFinalizeWithParametersShouldBeProxiable() + { + var method = typeof(MyClass).GetMethod( + "Finalize", + BindingFlags.Public | BindingFlags.Instance, + null, + new[] { typeof(int) }, + null); + + Assert.Multiple( + () => + { + Assert.That(method.ShouldBeProxiable(), Is.True); + Assert.That(method.IsProxiable(), Is.True); + }); } [Test] public void WhenProtectedNoVirtualPropertyThenShouldntBeProxiable() { var prop = typeof(ProtectedNoVirtualProperty).GetProperty("Aprop", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); - Assert.That(prop.ShouldBeProxiable(), Is.False); + Assert.That(prop.ShouldBeProxiable(), Is.False); } [Test] diff --git a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs index 7c170ebf0c6..d22b0d8fbf5 100644 --- a/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/SqlConverterAndMultiQuery/Fixture.cs @@ -43,7 +43,7 @@ public void MultiHqlShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) @@ -85,7 +85,7 @@ public void MultiCriteriaShouldThrowUserException() { var driver = Sfi.ConnectionProvider.Driver; if (!driver.SupportsMultipleQueries) - Assert.Ignore("Driver {0} does not support multi-queries", driver.GetType().FullName); + Assert.Ignore($"Driver {driver.GetType().FullName} does not support multi-queries"); using (var s = OpenSession()) using (s.BeginTransaction()) diff --git a/src/NHibernate.Test/NHibernate.Test.csproj b/src/NHibernate.Test/NHibernate.Test.csproj index 93cc3e5a31a..3e5c61bb6b4 100644 --- a/src/NHibernate.Test/NHibernate.Test.csproj +++ b/src/NHibernate.Test/NHibernate.Test.csproj @@ -4,10 +4,11 @@ The Unit Tests for NHibernate. $(NhAppTargetFrameworks) true - $(NoWarn);3001;3002;3003;3005;SYSLIB0003;SYSLIB0012 + $(NoWarn);3001;3002;3003;3005;8981;SYSLIB0003;SYSLIB0012 true + true - + Exe false @@ -34,8 +35,11 @@ Always + + PreserveNewest + - + @@ -46,28 +50,33 @@ + + Hql\Parser\CaseInsensitiveStringStream.cs + UtilityTest\AsyncReaderWriterLock.cs + UtilityTest\SetSnapShot.cs - - - - - - - - - - + + + + + + + + + + + - - + + @@ -76,17 +85,17 @@ - + - - + + - + - + - + diff --git a/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs b/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs index 854867a5cc7..ff4a358ee3f 100644 --- a/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Naturalid/Immutable/ImmutableNaturalIdFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs b/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs index 7149e89a67c..324db05247c 100644 --- a/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs +++ b/src/NHibernate.Test/Naturalid/Mutable/MutableNaturalIdFixture.cs @@ -21,9 +21,9 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.UseSecondLevelCache, "true"); - cfg.SetProperty(Environment.UseQueryCache, "true"); - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.UseSecondLevelCache, "true"); + configuration.SetProperty(Environment.UseQueryCache, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs b/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs index 62c8a151e45..5469c9f12b4 100644 --- a/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs +++ b/src/NHibernate.Test/Ondelete/JoinedSubclassFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.EFGJoinedSubclass.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs b/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs index 1af405c0a14..5ea4f1c967b 100644 --- a/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs +++ b/src/NHibernate.Test/Ondelete/OnDeleteFixture.cs @@ -19,7 +19,7 @@ protected override string[] Mappings protected override void Configure(Cfg.Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/Ondelete/ParentChildFixture.cs b/src/NHibernate.Test/Ondelete/ParentChildFixture.cs index d5303005de4..905de75dbe2 100644 --- a/src/NHibernate.Test/Ondelete/ParentChildFixture.cs +++ b/src/NHibernate.Test/Ondelete/ParentChildFixture.cs @@ -19,9 +19,9 @@ protected override string[] Mappings get { return new string[] { "Ondelete.ParentChild.hbm.xml" }; } } - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.GenerateStatistics, "true"); + configuration.SetProperty(Environment.GenerateStatistics, "true"); } [Test] diff --git a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs index 3d0e571ae9a..bfba5aed930 100644 --- a/src/NHibernate.Test/Pagination/CustomDialectFixture.cs +++ b/src/NHibernate.Test/Pagination/CustomDialectFixture.cs @@ -30,12 +30,12 @@ protected override void Configure(Configuration configuration) // Configure is called before Applies, must check here. if (!(Dialect is MsSql2005Dialect)) Assert.Ignore("Test is for SQL dialect only"); - var driverClass = ReflectHelper.ClassForName(cfg.GetProperty(Environment.ConnectionDriver)); + var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Environment.ConnectionDriver)); if (!typeof(SqlClientDriver).IsAssignableFrom(driverClass)) Assert.Ignore("Test is compatible only with Sql Server Client driver connection strings"); - cfg.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); - cfg.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); + configuration.SetProperty(Environment.Dialect, typeof(CustomMsSqlDialect).AssemblyQualifiedName); + configuration.SetProperty(Environment.ConnectionDriver, typeof(CustomMsSqlDriver).AssemblyQualifiedName); } private CustomMsSqlDialect CustomDialect diff --git a/src/NHibernate.Test/Pagination/PaginationFixture.cs b/src/NHibernate.Test/Pagination/PaginationFixture.cs index df9f578bc45..b921dbeda42 100644 --- a/src/NHibernate.Test/Pagination/PaginationFixture.cs +++ b/src/NHibernate.Test/Pagination/PaginationFixture.cs @@ -23,7 +23,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - cfg.SetProperty(Environment.DefaultBatchFetchSize, "20"); + configuration.SetProperty(Environment.DefaultBatchFetchSize, "20"); } [Test] diff --git a/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs b/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs index 054cba44957..9ecb5dd4377 100644 --- a/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs +++ b/src/NHibernate.Test/PropertyRef/ManyToManyPropertyRefFixture.cs @@ -1,16 +1,18 @@ +using System.Linq; using NHibernate.Criterion; +using NHibernate.Linq; using NUnit.Framework; namespace NHibernate.Test.PropertyRef { - [TestFixture] + [TestFixture(Description = "NH-2180 (GH-1214)")] public class ManyToManyPropertyRefFixture : TestCase { protected override string[] Mappings => new[] { "PropertyRef.ManyToManyWithPropertyRef.hbm.xml" }; protected override string MappingsAssembly => "NHibernate.Test"; - private object _manyAId; + private long _manyAId; protected override void OnSetUp() { @@ -23,7 +25,7 @@ protected override void OnSetUp() var manyB2 = new ManyB { Number = 8, Value = "a value of b2" }; var manyB3 = new ManyB { Number = 12, Value = "a value of b3" }; - _manyAId = session.Save(manyA); + _manyAId = (long) session.Save(manyA); session.Save(manyB1); session.Save(manyB2); session.Save(manyB3); @@ -133,5 +135,20 @@ bei NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueK Assert.That(loadedManyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); } + + [Test] + public void LinqFetch() + { + using (var session = OpenSession()) + { + var manyA = session + .Query() + .Where(a => a.Id == _manyAId) + .FetchMany(a => a.ManyBs) + .ToList() + .First(); + Assert.That(manyA.ManyBs, Has.Count.EqualTo(3).And.None.Null); + } + } } } diff --git a/src/NHibernate.Test/ProxyTest/PeVerifier.cs b/src/NHibernate.Test/ProxyTest/PeVerifier.cs index f5f4d027221..08db481d283 100644 --- a/src/NHibernate.Test/ProxyTest/PeVerifier.cs +++ b/src/NHibernate.Test/ProxyTest/PeVerifier.cs @@ -62,7 +62,11 @@ public void AssertIsValid() var result = process.ExitCode + " code "; if (process.ExitCode != 0) - Assert.Fail("PeVerify reported error(s): " + Environment.NewLine + processOutput, result); + Assert.Fail( + $@"PeVerify reported error(s): +{processOutput} + +{result}"); } } } diff --git a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs index acebb19a929..db2a020d380 100644 --- a/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs +++ b/src/NHibernate.Test/QueryTest/MultiCriteriaFixture.cs @@ -29,8 +29,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.GenerateStatistics, "true"); } diff --git a/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs b/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs index 9957275d67a..f65135564b1 100644 --- a/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs +++ b/src/NHibernate.Test/ReadOnly/AbstractReadOnlyTest.cs @@ -13,7 +13,6 @@ protected override string MappingsAssembly protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.GenerateStatistics, "true"); configuration.SetProperty(Environment.BatchSize, "0"); } diff --git a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs index 6ef31d2ae23..0773dd3e83e 100644 --- a/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs +++ b/src/NHibernate.Test/ReadOnly/ReadOnlyVersionedNodes.cs @@ -624,7 +624,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -637,7 +637,7 @@ public void MergeDetachedChildWithNewParentCommitWithReadOnlyChild() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); @@ -675,7 +675,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() t.Commit(); } - AssertUpdateCount(0); // NH-specific: Hibernate issues a separate UPDATE for the version number + AssertUpdateCount(1); AssertInsertCount(1); ClearCounts(); using (var s = OpenSession()) @@ -688,8 +688,7 @@ public void GetChildMakeReadOnlyThenMergeDetachedChildWithNewParent() Assert.That(child.Version, Is.EqualTo(1)); Assert.That(parent, Is.Not.Null); Assert.That(parent.Children.Count, Is.EqualTo(0)); - Assert.That(parent.Version, Is.EqualTo(1)); - // NH-specific: Hibernate incorrectly increments version number, NH does not + Assert.That(parent.Version, Is.EqualTo(2)); s.SetReadOnly(parent, true); s.SetReadOnly(child, true); s.Delete(parent); diff --git a/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs b/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs index f8c8581363e..731a0674890 100644 --- a/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs +++ b/src/NHibernate.Test/SecondLevelCacheTest/SecondLevelCacheTest.cs @@ -24,7 +24,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); configuration.Properties[Environment.CacheProvider] = typeof(HashtableCacheProvider).AssemblyQualifiedName; configuration.Properties[Environment.UseQueryCache] = "true"; } @@ -262,4 +261,4 @@ public void SecondLevelCacheWithHqlQueries() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs index 795bddf586c..ce076e007bd 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlInsertBuilderFixture.cs @@ -26,7 +26,9 @@ public void InsertSqlStringTest() insert.AddColumn("intColumn", NHibernateUtil.Int32); insert.AddColumn("longColumn", NHibernateUtil.Int64); +#pragma warning disable CS0618 // Type or member is obsolete insert.AddColumn("literalColumn", false, (ILiteralType) NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete insert.AddColumn("stringColumn", 5.ToString()); SqlCommandInfo sqlCommand = insert.ToSqlCommandInfo(); @@ -53,7 +55,9 @@ public void Commented() insert.SetTableName("test_insert_builder"); - insert.AddColumn("stringColumn", "aSQLValue", (ILiteralType)NHibernateUtil.String); +#pragma warning disable CS0618 // Type or member is obsolete + insert.AddColumn("stringColumn", "aSQLValue", (ILiteralType)NHibernateUtil.AnsiString); +#pragma warning restore CS0618 // Type or member is obsolete insert.SetComment("Test insert"); string expectedSql = "/* Test insert */ INSERT INTO test_insert_builder (stringColumn) VALUES ('aSQLValue')"; @@ -71,7 +75,9 @@ public void MixingParametersAndValues() insert.SetTableName("test_insert_builder"); +#pragma warning disable CS0618 // Type or member is obsolete insert.AddColumn("literalColumn", false, (ILiteralType)NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete insert.AddColumn("intColumn", NHibernateUtil.Int32); insert.AddColumn("stringColumn", 5.ToString()); insert.AddColumn("longColumn", NHibernateUtil.Int64); @@ -89,4 +95,4 @@ public void MixingParametersAndValues() Assert.AreEqual(SqlTypeFactory.Int64, actualParameterTypes[1], "Second Parameter Type"); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs index 361b2b1525e..df244dff0eb 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlStringFixture.cs @@ -263,8 +263,8 @@ public void TrimAllParam() Parameter p2 = Parameter.Placeholder; SqlString sql = new SqlString(new object[] { p1, p2 }); - sql = sql.Trim(); + Assert.That(ReferenceEquals(sql, sql.Trim()), Is.True); Assert.AreEqual("??", sql.ToString()); } @@ -434,7 +434,8 @@ public void ParameterPropertyShouldReturnNewInstances() Assert.IsNull(parameters2[0].ParameterPosition); // more simple version of the test - Assert.That(Parameter.Placeholder, Is.Not.SameAs(Parameter.Placeholder)); + var placeholder = Parameter.Placeholder; + Assert.That(placeholder, Is.Not.SameAs(Parameter.Placeholder)); } [Test] diff --git a/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs index 3cb38216fad..54332e78098 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlTokenizerFixture.cs @@ -115,15 +115,14 @@ private static void VerifyTokenizer(string sql, params ExpectedToken[] expectedT { if (tokenIndex >= expectedTokens.Length) { - Assert.Fail("Tokenizer returns more than expected '{0}' tokens. \nSQL: {1}\nLast Token: {2}({3})", - expectedTokens.Length, sql, token.TokenType, token.Value); + Assert.Fail($"Tokenizer returns more than expected '{expectedTokens.Length}' tokens. \nSQL: {sql}\nLast Token: {token.TokenType}({token.Value})"); } var expectedToken = expectedTokens[tokenIndex]; - Assert.That(token.TokenType, Is.EqualTo(expectedToken.TokenType), "[Token #{0} in '{1}']TokenType", tokenIndex, sql); - Assert.That(token.Value, Is.EqualTo(expectedToken.Value), "[Token #{0} in {1}]Value", tokenIndex, sql); - Assert.That(token.SqlIndex, Is.EqualTo(sqlIndex), "[Token #{0} in {1}]SqlIndex", tokenIndex, sql); - Assert.That(token.Length, Is.EqualTo(expectedToken.Length), "[Token #{0} in {1}]Length", tokenIndex, sql); + Assert.That(token.TokenType, Is.EqualTo(expectedToken.TokenType), $"[Token #{tokenIndex} in '{sql}']TokenType"); + Assert.That(token.Value, Is.EqualTo(expectedToken.Value), $"[Token #{tokenIndex} in {sql}]Value"); + Assert.That(token.SqlIndex, Is.EqualTo(sqlIndex), $"[Token #{tokenIndex} in {sql}]SqlIndex"); + Assert.That(token.Length, Is.EqualTo(expectedToken.Length), $"[Token #{tokenIndex} in {sql}]Length"); tokenIndex++; sqlIndex += expectedToken.Length; @@ -131,7 +130,7 @@ private static void VerifyTokenizer(string sql, params ExpectedToken[] expectedT if (tokenIndex < expectedTokens.Length) { - Assert.Fail("Tokenizer returns less than expected '{0}' tokens.\nSQL: {1}", expectedTokens.Length, sql); + Assert.Fail($"Tokenizer returns less than expected '{expectedTokens.Length}' tokens.\nSQL: {sql}"); } } diff --git a/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs b/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs index c0bd0ece22b..96a47f2e245 100644 --- a/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs +++ b/src/NHibernate.Test/SqlCommandTest/SqlUpdateBuilderFixture.cs @@ -28,7 +28,9 @@ public void UpdateStringSqlTest() update.AddColumns(new string[] {"intColumn"}, NHibernateUtil.Int32); update.AddColumns(new string[] {"longColumn"}, NHibernateUtil.Int64); +#pragma warning disable CS0618 // Type or member is obsolete update.AddColumn("literalColumn", false, (ILiteralType) NHibernateUtil.Boolean); +#pragma warning restore CS0618 // Type or member is obsolete update.AddColumn("stringColumn", 5.ToString()); update.SetIdentityColumn(new string[] {"decimalColumn"}, NHibernateUtil.Decimal); @@ -60,4 +62,4 @@ public void UpdateStringSqlTest() Assert.AreEqual(expectedParameterTypes[3], actualParameterTypes[3], "fourthParam Type"); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs b/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs index 8ee760763c3..79a157d4086 100644 --- a/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs +++ b/src/NHibernate.Test/SqlTest/Custom/CustomSQLSupportTest.cs @@ -48,10 +48,10 @@ public void HandSQL() s = OpenSession(); t = s.BeginTransaction(); jboss = (Organization)s.Get(typeof(Organization), orgId); - Assert.AreEqual(jboss.Employments.Count, 2); + Assert.AreEqual(2, jboss.Employments.Count); emp = (Employment)GetFirstItem(jboss.Employments); gavin = emp.Employee; - Assert.AreEqual(gavin.Name, "GAVIN"); + Assert.AreEqual("GAVIN", gavin.Name); Assert.AreEqual(s.GetCurrentLockMode(gavin), LockMode.Upgrade); emp.EndDate = DateTime.Today; Employment emp3 = new Employment(gavin, jboss, "US"); @@ -64,7 +64,7 @@ public void HandSQL() IEnumerator iter = s.GetNamedQuery("allOrganizationsWithEmployees").List().GetEnumerator(); Assert.IsTrue(iter.MoveNext()); Organization o = (Organization)iter.Current; - Assert.AreEqual(o.Employments.Count, 3); + Assert.AreEqual(3, o.Employments.Count); foreach (Employment e in o.Employments) { diff --git a/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs b/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs index 73bb920d571..e965bf6362f 100644 --- a/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs +++ b/src/NHibernate.Test/SqlTest/Custom/CustomStoredProcSupportTest.cs @@ -15,8 +15,8 @@ public void ScalarStoredProcedure() namedQuery.SetInt64("number", 43L); IList list = namedQuery.List(); object[] o = (object[])list[0]; - Assert.AreEqual(o[0], "getAll"); - Assert.AreEqual(o[1], 43L); + Assert.AreEqual("getAll", o[0]); + Assert.AreEqual(43L, o[1]); s.Close(); } @@ -30,16 +30,16 @@ public void ParameterHandling() namedQuery.SetInt64(1, 20L); IList list = namedQuery.List(); object[] o = (Object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); namedQuery = s.GetNamedQuery("paramhandling_mixed"); namedQuery.SetInt64(0, 10L); namedQuery.SetInt64("second", 20L); list = namedQuery.List(); o = (object[])list[0]; - Assert.AreEqual(o[0], 10L); - Assert.AreEqual(o[1], 20L); + Assert.AreEqual(10L, o[0]); + Assert.AreEqual(20L, o[1]); s.Close(); } diff --git a/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs b/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs index 97dd424543b..c7b692d9a8f 100644 --- a/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs +++ b/src/NHibernate.Test/SqlTest/Identity/IdentityInsertWithStoredProcsTest.cs @@ -13,7 +13,6 @@ protected override string MappingsAssembly protected override void Configure(NHibernate.Cfg.Configuration configuration) { - base.Configure(configuration); configuration.SetProperty(Environment.FormatSql, "false"); } diff --git a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs index 38c395298df..26cadf8f47f 100644 --- a/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs +++ b/src/NHibernate.Test/SqlTest/Query/NativeSQLQueriesFixture.cs @@ -119,7 +119,7 @@ public void SQLQueryInterface() .AddJoin("emp", "org.employments") .AddJoin("pers", "emp.employee") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); } @@ -135,7 +135,7 @@ public void SQLQueryInterface() .AddJoin("emp", "org.employments") .SetResultTransformer(new DistinctRootEntityResultTransformer()) .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); t.Commit(); s.Close(); @@ -172,7 +172,7 @@ public void SQLQueryInterfaceCacheable() .AddJoin("pers", "emp.employee") .SetCacheable(true) .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); } @@ -189,7 +189,7 @@ public void SQLQueryInterfaceCacheable() .SetCacheable(true) .SetResultTransformer(new DistinctRootEntityResultTransformer()) .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); t.Commit(); s.Close(); @@ -460,12 +460,12 @@ public void ResultSetMappingDefinition() IList l = s.CreateSQLQuery(OrgEmpRegionSQL) .SetResultSetMapping("org-emp-regionCode") .List(); - Assert.AreEqual(l.Count, 2); + Assert.AreEqual(2, l.Count); l = s.CreateSQLQuery(OrgEmpPersonSQL) .SetResultSetMapping("org-emp-person") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Commit(); s.Close(); @@ -504,12 +504,12 @@ public void ScalarValues() IEnumerator iter = s.GetNamedQuery("orgNamesAndOrgs").List().GetEnumerator(); iter.MoveNext(); object[] o = (object[]) iter.Current; - Assert.AreEqual(o[0], "IFA"); - Assert.AreEqual(((Organization) o[1]).Name, "IFA"); + Assert.AreEqual("IFA", o[0]); + Assert.AreEqual("IFA", ((Organization) o[1]).Name); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[0], "JBoss"); - Assert.AreEqual(((Organization) o[1]).Name, "JBoss"); + Assert.AreEqual("JBoss", o[0]); + Assert.AreEqual("JBoss", ((Organization) o[1]).Name); t.Commit(); s.Close(); @@ -524,13 +524,13 @@ public void ScalarValues() Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); Assert.AreEqual("IFA", ((Organization) row[0]).Name); - Assert.AreEqual(row[1], "IFA"); + Assert.AreEqual("IFA", row[1]); iter.MoveNext(); row = (object[]) iter.Current; Assert.AreEqual(typeof(Organization), row[0].GetType(), "expecting non-scalar result first"); Assert.AreEqual(typeof(string), row[1].GetType(), "expecting scalar result second"); - Assert.AreEqual(((Organization) row[0]).Name, "JBoss"); - Assert.AreEqual(row[1], "JBoss"); + Assert.AreEqual("JBoss", ((Organization) row[0]).Name); + Assert.AreEqual("JBoss", row[1]); Assert.IsFalse(iter.MoveNext()); t.Commit(); @@ -542,11 +542,11 @@ public void ScalarValues() iter = s.GetNamedQuery("orgIdsAndOrgNames").List().GetEnumerator(); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "IFA"); + Assert.AreEqual("IFA", o[1]); Assert.AreEqual(o[0], idIfa); iter.MoveNext(); o = (object[]) iter.Current; - Assert.AreEqual(o[1], "JBoss"); + Assert.AreEqual("JBoss", o[1]); Assert.AreEqual(o[0], idJBoss); t.Commit(); @@ -769,7 +769,7 @@ public void AutoDetectAliasing() IQuery queryWithCollection = s.GetNamedQuery("organizationEmploymentsExplicitAliases"); queryWithCollection.SetInt64("id", jboss.Id); list = queryWithCollection.List(); - Assert.AreEqual(list.Count, 1); + Assert.AreEqual(1, list.Count); s.Clear(); @@ -860,7 +860,7 @@ public void MixAndMatchEntityScalar() IList l = s.CreateSQLQuery("select name, id, flength, name as scalarName from Speech") .SetResultSetMapping("speech") .List(); - Assert.AreEqual(l.Count, 1); + Assert.AreEqual(1, l.Count); t.Rollback(); s.Close(); @@ -939,7 +939,7 @@ public void CanSetResultTransformerOnFutureQuery() .SetResultTransformer(transformer) .Future(); - Assert.AreEqual(l.GetEnumerable().Count(), 1); + Assert.AreEqual(1, l.GetEnumerable().Count()); Assert.AreEqual("Ricardo", l.GetEnumerable().ElementAt(0)[0]); Assert.IsTrue(transformer.TransformListCalled); Assert.IsTrue(transformer.TransformTupleCalled); @@ -984,7 +984,7 @@ public void CanExecuteFutureList() .CreateSQLQuery("select Name from Person") .Future(); - Assert.AreEqual(l.GetEnumerable().Count(), 1); + Assert.AreEqual(1, l.GetEnumerable().Count()); Assert.AreEqual("Ricardo", l.GetEnumerable().ElementAt(0)); } } diff --git a/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs b/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs index 90501423ffc..d28827c4a35 100644 --- a/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs +++ b/src/NHibernate.Test/Stateless/StatelessSessionQueryFixture.cs @@ -19,8 +19,7 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - cfg.SetProperty(Environment.MaxFetchDepth, 1.ToString()); + configuration.SetProperty(Environment.MaxFetchDepth, 1.ToString()); } protected override bool AppliesTo(Dialect.Dialect dialect) diff --git a/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs b/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs index 1f18e170e8a..722bb604af2 100644 --- a/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs +++ b/src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs @@ -816,6 +816,50 @@ private static BinaryFormatter GetFormatter() #endif } +#if NETCOREAPP3_1_OR_GREATER + public interface IWithStaticMethods + { + // C# 8 + static void StaticMethod() + { + } + +#if NET7_0_OR_GREATER + // C# 11 + static abstract void StaticAbstractMethod(); + + // C# 11 + static virtual void StaticVirtualMethod() + { + } +#endif + } + + public class ClassWithStaticInterfaceMethods : IWithStaticMethods + { + public static void StaticAbstractMethod() + { + } + } + + [Test(Description = "GH3295")] + public void VerifyProxyForClassWithStaticInterfaceMethod() + { + var factory = new StaticProxyFactory(); + factory.PostInstantiate( + typeof(ClassWithStaticInterfaceMethods).FullName, + typeof(ClassWithStaticInterfaceMethods), + new HashSet { typeof(INHibernateProxy) }, + null, null, null, true); + + var proxy = factory.GetProxy(1, null); + Assert.That(proxy, Is.Not.Null); + Assert.That(proxy, Is.InstanceOf()); + + Assert.That(factory.GetFieldInterceptionProxy(), Is.InstanceOf()); + } +#endif + #if NETFX private static void VerifyGeneratedAssembly(System.Action assemblyGenerator) { diff --git a/src/NHibernate.Test/SubclassFilterTest/JoinedSubclassFilterTest.cs b/src/NHibernate.Test/SubclassFilterTest/JoinedSubclassFilterTest.cs index c69487579a2..07494cc436f 100644 --- a/src/NHibernate.Test/SubclassFilterTest/JoinedSubclassFilterTest.cs +++ b/src/NHibernate.Test/SubclassFilterTest/JoinedSubclassFilterTest.cs @@ -1,4 +1,3 @@ -using System; using System.Collections; using NUnit.Framework; using System.Linq; @@ -8,25 +7,33 @@ namespace NHibernate.Test.SubclassFilterTest [TestFixture] public class JoinedSubclassFilterTest : TestCase { - protected override string[] Mappings + protected override string[] Mappings => new[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; + + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override void OnSetUp() { - get { return new string[] {"SubclassFilterTest.joined-subclass.hbm.xml"}; } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + PrepareTestData(s); + t.Commit(); } - protected override string MappingsAssembly + protected override void OnTearDown() { - get { return "NHibernate.Test"; } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.Delete("from Customer c where c.ContactOwner is not null"); + s.Delete("from Employee e where e.Manager is not null"); + s.Delete("from Person"); + t.Commit(); } [Test] public void FiltersWithSubclass() { - ISession s = OpenSession(); + using var s = OpenSession(); s.EnableFilter("region").SetParameter("userRegion", "US"); - ITransaction t = s.BeginTransaction(); - - PrepareTestData(s); - s.Clear(); IList results; @@ -49,14 +56,6 @@ public void FiltersWithSubclass() } s.Clear(); - // TODO : currently impossible to define a collection-level filter w/ - // joined-subclass elements that will filter based on a superclass - // column and function correctly in (theta only?) outer joins; - // this is consistent with the behaviour of a collection-level where. - // this might be one argument for "pulling" the attached class-level - // filters into collection assocations, - // although we'd need some way to apply the appropriate alias in that - // scenario. results = s.CreateQuery("from Person as p left join fetch p.Minions").List().Distinct().ToList(); Assert.AreEqual(4, results.Count, "Incorrect qry result count"); foreach (Person p in results) @@ -82,25 +81,12 @@ public void FiltersWithSubclass() break; } } - - t.Commit(); - s.Close(); - - s = OpenSession(); - t = s.BeginTransaction(); - s.Delete("from Customer c where c.ContactOwner is not null"); - s.Delete("from Employee e where e.Manager is not null"); - s.Delete("from Person"); - t.Commit(); - s.Close(); } [Test] public void FilterCollectionWithSubclass1() { using var s = OpenSession(); - using var t = s.BeginTransaction(); - PrepareTestData(s); s.EnableFilter("minionsWithManager"); @@ -109,14 +95,10 @@ public void FilterCollectionWithSubclass1() Assert.That(employees[0].Minions.Count, Is.EqualTo(2)); } - [KnownBug("GH-3079: Collection filter on subclass columns")] - [Test] + [Test(Description = "GH-3079: Collection filter on subclass columns")] public void FilterCollectionWithSubclass2() { using var s = OpenSession(); - using var t = s.BeginTransaction(); - PrepareTestData(s); - s.EnableFilter("minionsRegion").SetParameter("userRegion", "US"); var employees = s.Query().Where(x => x.Minions.Any()).ToList(); @@ -160,8 +142,6 @@ private static void PrepareTestData(ISession s) s.Save(john); s.Save(cust); s.Save(ups); - - s.Flush(); } } } diff --git a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs index 9fd00d6e6c6..7d05eac7cd6 100644 --- a/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs +++ b/src/NHibernate.Test/SubselectFetchTest/SubselectFetchFixture.cs @@ -9,9 +9,9 @@ namespace NHibernate.Test.SubselectFetchTest [TestFixture] public class SubselectFetchFixture : TestCase { - protected override void Configure(Configuration cfg) + protected override void Configure(Configuration configuration) { - cfg.SetProperty(Cfg.Environment.GenerateStatistics, "true"); + configuration.SetProperty(Cfg.Environment.GenerateStatistics, "true"); } [Test] @@ -44,24 +44,24 @@ public void SubselectFetchHql() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -109,24 +109,24 @@ public void SubselectFetchNamedParam() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -174,24 +174,24 @@ public void SubselectFetchPosParam() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); @@ -240,8 +240,8 @@ public void SubselectFetchWithLimit() Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(0, p.MoreChildren.Count); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); @@ -250,8 +250,8 @@ public void SubselectFetchWithLimit() r = (Parent) s.Get(typeof(Parent), r.Name); Assert.IsTrue(NHibernateUtil.IsInitialized(r.Children)); // The test for True is the test of H3.2 Assert.IsFalse(NHibernateUtil.IsInitialized(r.MoreChildren)); - Assert.AreEqual(r.Children.Count, 1); - Assert.AreEqual(r.MoreChildren.Count, 0); + Assert.AreEqual(1, r.Children.Count); + Assert.AreEqual(0, r.MoreChildren.Count); s.Delete(p); s.Delete(q); @@ -333,24 +333,24 @@ public void SubselectFetchCriteria() Assert.IsFalse(NHibernateUtil.IsInitialized(p.Children)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(p.Children.Count, 2); + Assert.AreEqual(2, p.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(p.Children[0])); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children)); - Assert.AreEqual(q.Children.Count, 2); + Assert.AreEqual(2, q.Children.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.Children[0])); Assert.IsFalse(NHibernateUtil.IsInitialized(p.MoreChildren)); Assert.IsFalse(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(p.MoreChildren.Count, 0); + Assert.AreEqual(0, p.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren)); - Assert.AreEqual(q.MoreChildren.Count, 2); + Assert.AreEqual(2, q.MoreChildren.Count); Assert.IsTrue(NHibernateUtil.IsInitialized(q.MoreChildren[0])); diff --git a/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs index b7d931e0809..c16175432c9 100644 --- a/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/DistributedSystemTransactionFixture.cs @@ -362,7 +362,7 @@ public void MultiThreadedTransaction() var errors = mtr.GetErrors(); if (errors.Length > 0) { - Assert.Fail("One or more thread failed, found {0} errors. First exception: {1}", errors.Length, errors[0]); + Assert.Fail($"One or more thread failed, found {errors.Length} errors. First exception: {errors[0]}"); } } @@ -539,10 +539,11 @@ public void CanUseSessionOutsideOfScopeAfterScope(bool explicitFlush) } var count = 0; Assert.DoesNotThrow(() => count = s.Query().Count(), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } diff --git a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs index e5fb6fd46c0..1a42ae71e19 100644 --- a/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs +++ b/src/NHibernate.Test/SystemTransactions/SystemTransactionFixture.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -18,6 +19,13 @@ public class SystemTransactionFixture : SystemTransactionFixtureBase protected override bool UseConnectionOnSystemTransactionPrepare => true; protected override bool AutoJoinTransaction => true; + protected override void OnTearDown() + { + base.OnTearDown(); + // The SupportsTransactionTimeout test may change this, restore it to its default value. + FailOnNotClosedSession = true; + } + [Test] public void WillNotCrashOnPrepareFailure() { @@ -276,10 +284,11 @@ public void CanUseSessionOutsideOfScopeAfterScope(bool explicitFlush) } var count = 0; Assert.DoesNotThrow(() => count = s.Query().Count(), "Failed using the session after scope."); - if (count != 1) + const int expectedCount = 1; + if (count != expectedCount) // We are not testing that here, so just issue a warning. Do not use DodgeTransactionCompletionDelayIfRequired // before previous assert. We want to ascertain the session is usable in any cases. - Assert.Warn("Unexpected entity count: {0} instead of {1}. The transaction seems to have a delayed commit.", count, 1); + Assert.Warn($"Unexpected entity count: {count} instead of {expectedCount}. The transaction seems to have a delayed commit."); } } @@ -643,6 +652,151 @@ public void CanUseSessionWithManyDependentTransaction(bool explicitFlush) } } + // This test check a concurrency issue hard to reproduce. If it is flaky, it has to be considered failing. + // In such case, raise triesCount to investigate it locally with more chances of triggering the trouble. + [Test] + public void SupportsTransactionTimeout() + { + Assume.That(TestDialect.SupportsTransactionScopeTimeouts, Is.True, "The tested dialect is not supported for transaction scope timeouts."); + // Other special cases: ODBC and SAP SQL Anywhere succeed this test only with transaction.ignore_session_synchronization_failures + // enabled. + // They freeze the session during the transaction cancellation. To avoid the test to be very long, the synchronization + // lock timeout should be lowered too. + + // A concurrency issue exists with the legacy setting allowing to use the session from transaction completion, which + // may cause session leaks. Ignore them. + FailOnNotClosedSession = !UseConnectionOnSystemTransactionPrepare; + + // Test case adapted from https://github.com/kaksmet/NHibBugRepro + + // Create some test data. + const int entitiesCount = 5000; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + for (var i = 0; i < entitiesCount; i++) + { + var person = new Person + { + NotNullData = Guid.NewGuid().ToString() + }; + + s.Save(person); + } + + t.Commit(); + } + + // Setup unhandled exception catcher. + _unhandledExceptions = new ConcurrentBag(); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + try + { + // Generate transaction timeouts. + const int triesCount = 100; + var txOptions = new TransactionOptions { Timeout = TimeSpan.FromMilliseconds(1) }; + var timeoutsCount = 0; + for (var i = 0; i < triesCount; i++) + { + try + { + using var txScope = new TransactionScope(TransactionScopeOption.Required, txOptions); + using var session = OpenSession(); + var data = session.CreateCriteria().List(); + Assert.That(data, Has.Count.EqualTo(entitiesCount), "Unexpected count of loaded entities."); + Thread.Sleep(2); + var count = session.Query().Count(); + Assert.That(count, Is.EqualTo(entitiesCount), "Unexpected entities count."); + txScope.Complete(); + } + catch + { + // Assume that is a transaction timeout. It may cause various failures, of which some are hard to identify. + timeoutsCount++; + } + // If in need of checking some specific failures, the following code may be used instead: + /* + catch (Exception ex) + { + var currentEx = ex; + // Depending on where the transaction aborption has broken NHibernate processing, we may + // get various exceptions, like directly a TransactionAbortedException with an inner + // TimeoutException, or a HibernateException encapsulating a TransactionException with a + // timeout, ... + bool isTransactionException, isTimeout; + do + { + isTransactionException = currentEx is System.Transactions.TransactionException; + isTimeout = isTransactionException && currentEx is TransactionAbortedException; + currentEx = currentEx.InnerException; + } + while (!isTransactionException && currentEx != null); + while (!isTimeout && currentEx != null) + { + isTimeout = currentEx is TimeoutException; + currentEx = currentEx?.InnerException; + } + + if (!isTimeout) + { + // We may also get a GenericADOException with an InvalidOperationException stating the + // transaction associated to the connection is no more active but not yet suppressed, + // and that for executing some SQL, we need to suppress it. That is a weak way of + // identifying the case, especially with the many localizations of the message. + currentEx = ex; + do + { + isTimeout = currentEx is InvalidOperationException && currentEx.Message.Contains("SQL"); + currentEx = currentEx?.InnerException; + } + while (!isTimeout && currentEx != null); + } + + if (isTimeout) + timeoutsCount++; + else + throw; + } + */ + } + + Assert.That( + _unhandledExceptions.Count, + Is.EqualTo(0), + $"Unhandled exceptions have occurred: {string.Join(@" + +", _unhandledExceptions)}"); + + // Despite the Thread sleep and the count of entities to load, this test may get the timeout only for slightly + // more than 10% of the attempts. + Warn.Unless(timeoutsCount, Is.GreaterThan(5), "The test should have generated more timeouts."); + } + finally + { + AppDomain.CurrentDomain.UnhandledException -= CurrentDomain_UnhandledException; + } + } + + private ConcurrentBag _unhandledExceptions; + + private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + if (e.ExceptionObject is Exception exception) + { + // Ascertain NHibernate is involved. Some unhandled exceptions occur due to the + // TransactionScope timeout operating on an unexpected thread for the data provider. + var isNHibernateInvolved = false; + while (exception != null && !isNHibernateInvolved) + { + isNHibernateInvolved = exception.StackTrace != null && exception.StackTrace.ToLowerInvariant().Contains("nhibernate"); + exception = exception.InnerException; + } + if (!isNHibernateInvolved) + return; + } + _unhandledExceptions.Add(e.ExceptionObject); + } + [Theory, Explicit("Bench")] public void BenchTransactionAccess(bool inTransaction) { diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index c58d819ed64..1335b6a722a 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -54,6 +54,8 @@ protected TestDialect TestDialect get { return _testDialect ?? (_testDialect = TestDialect.GetTestDialect(Dialect)); } } + protected bool FailOnNotClosedSession { get; set; } = true; + /// /// Mapping files used in the TestCase /// @@ -157,6 +159,9 @@ public void TearDown() { var testResult = TestContext.CurrentContext.Result; var fail = false; + var wereClosed = true; + // In case the test Teardown needs to switch it off for other tests, back it up. + var failOnNotClosedSession = FailOnNotClosedSession; var testOwnTearDownDone = false; string badCleanupMessage = null; try @@ -170,12 +175,12 @@ public void TearDown() { try { - var wereClosed = _sessionFactory.CheckSessionsWereClosed(); + wereClosed = _sessionFactory.CheckSessionsWereClosed(); var wasCleaned = CheckDatabaseWasCleaned(); var wereConnectionsClosed = CheckConnectionsWereClosed(); - fail = !wereClosed || !wasCleaned || !wereConnectionsClosed; + fail = !wereClosed && failOnNotClosedSession || !wasCleaned || !wereConnectionsClosed; - if (fail) + if (fail || !wereClosed) { badCleanupMessage = "Test didn't clean up after itself. session closed: " + wereClosed + "; database cleaned: " + wasCleaned @@ -213,6 +218,10 @@ public void TearDown() { Assert.Fail(badCleanupMessage); } + else if (!wereClosed) + { + Assert.Warn(badCleanupMessage); + } } private string GetCombinedFailureMessage(TestContext.ResultAdapter result, string tearDownFailure, string tearDownStackTrace) @@ -284,10 +293,10 @@ protected void Configure() { cfg = TestConfigurationHelper.GetDefaultConfiguration(); - AddMappings(cfg); - Configure(cfg); + AddMappings(cfg); + ApplyCacheSettings(cfg); } diff --git a/src/NHibernate.Test/TestDialect.cs b/src/NHibernate.Test/TestDialect.cs index 49b2f7e0f69..316d7b68fd8 100644 --- a/src/NHibernate.Test/TestDialect.cs +++ b/src/NHibernate.Test/TestDialect.cs @@ -105,7 +105,7 @@ public bool SupportsEmptyInsertsOrHasNonIdentityNativeGenerator /// public virtual bool SupportsNonDataBoundCondition => true; - public bool SupportsSqlType(SqlType sqlType) + public virtual bool SupportsSqlType(SqlType sqlType) { try { @@ -123,10 +123,15 @@ public bool SupportsSqlType(SqlType sqlType) /// public virtual bool SupportsModuloOnDecimal => true; + /// + /// Supports sub-selects in order by clause + /// + public virtual bool SupportsSubSelectsInOrderBy => _dialect.SupportsScalarSubSelects; + /// /// Supports aggregating sub-selects in order by clause /// - public virtual bool SupportsAggregatingScalarSubSelectsInOrderBy => _dialect.SupportsScalarSubSelects; + public virtual bool SupportsAggregatingScalarSubSelectsInOrderBy => SupportsSubSelectsInOrderBy; /// /// Supports order by and limits/top in correlated sub-queries @@ -177,6 +182,11 @@ public bool SupportsSqlType(SqlType sqlType) /// public virtual bool SupportsDependentTransaction => true; + /// + /// Transaction scope timeouts occur on a dedicated thread which wrecks some data providers. + /// + public virtual bool SupportsTransactionScopeTimeouts => true; + /// /// Some databases (provider?) fails to compute adequate column types for queries which columns /// computing include a parameter value. @@ -203,5 +213,10 @@ public bool SupportsSqlType(SqlType sqlType) /// Returns true if you can cancel a query. /// public virtual bool SupportsCancelQuery => true; + + /// + /// Some databases (MySql) don't support using main table aliases in subquery inside join ON clause + /// + public virtual bool SupportsCorrelatedColumnsInSubselectJoin => true; } } diff --git a/src/NHibernate.Test/TestDialects/DB2TestDialect.cs b/src/NHibernate.Test/TestDialects/DB2TestDialect.cs new file mode 100644 index 00000000000..a96b57eeb24 --- /dev/null +++ b/src/NHibernate.Test/TestDialects/DB2TestDialect.cs @@ -0,0 +1,16 @@ +namespace NHibernate.Test.TestDialects +{ + public class DB2TestDialect: TestDialect + { + public DB2TestDialect(Dialect.Dialect dialect) : base(dialect) + { + } + + public override bool HasBrokenTypeInferenceOnSelectedParameters => true; + public override bool SupportsCancelQuery => false; + public override bool SupportsComplexExpressionInGroupBy => false; + public override bool SupportsNonDataBoundCondition => false; + public override bool SupportsSelectForUpdateWithPaging => false; + public override bool SupportsSubSelectsInOrderBy => false; + } +} diff --git a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs index 0ec57f43bc6..d37bef44dd5 100644 --- a/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/MySQL5TestDialect.cs @@ -14,5 +14,17 @@ public MySQL5TestDialect(Dialect.Dialect dialect) /// This behaviour is documented at: http://dev.mysql.com/doc/refman/5.6/en/update.html /// public override bool SupportsModifyAndSelectSameTable => false; + + /// + /// A correlated column can be present only in the subquery's WHERE clause (and not in the SELECT list, + /// a JOIN or ORDER BY clause, a GROUP BY list, or a HAVING clause). Nor can there be any correlated column inside a derived table in the subquery's FROM list. + /// See https://dev.mysql.com/doc/refman/8.0/en/correlated-subqueries.html + /// + public override bool SupportsCorrelatedColumnsInSubselectJoin => false; + + /// + /// MySQL data provider may be wrecked by transaction scope timeouts to the point of causing even the teardown to fail. + /// + public override bool SupportsTransactionScopeTimeouts => false; } } diff --git a/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs b/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs index 4a5fb8d2322..281676a6c71 100644 --- a/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs +++ b/src/NHibernate.Test/TestDialects/Oracle10gTestDialect.cs @@ -1,4 +1,6 @@ -using System.Runtime.InteropServices; +using System.Data; +using System.Runtime.InteropServices; +using NHibernate.SqlTypes; namespace NHibernate.Test.TestDialects { @@ -15,6 +17,16 @@ public Oracle10gTestDialect(Dialect.Dialect dialect) : base(dialect) public override bool SupportsAggregateInSubSelect => true; + public override bool SupportsSqlType(SqlType sqlType) + { + // The Oracle dialects define types for DbType the Oracle driver does not support. + return sqlType.DbType switch + { + DbType.UInt16 or DbType.UInt32 or DbType.UInt64 => false, + _ => base.SupportsSqlType(sqlType) + }; + } + /// /// Canceling a query hangs under Linux with OracleManagedDataClientDriver 21.6.1. public override bool SupportsCancelQuery => !RuntimeInformation.IsOSPlatform(OSPlatform.Linux); diff --git a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs index 35a35092ce3..249d884b67d 100644 --- a/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs +++ b/src/NHibernate.Test/TestDialects/SapSQLAnywhere17TestDialect.cs @@ -1,4 +1,7 @@ -namespace NHibernate.Test.TestDialects +using System.Data; +using NHibernate.SqlTypes; + +namespace NHibernate.Test.TestDialects { public class SapSQLAnywhere17TestDialect : TestDialect { @@ -40,8 +43,18 @@ public SapSQLAnywhere17TestDialect(Dialect.Dialect dialect) public override bool HasBrokenTypeInferenceOnSelectedParameters => true; /// - /// Does not support SELECT FOR UPDATE + /// Does not support SELECT FOR UPDATE. /// public override bool SupportsSelectForUpdate => false; + + public override bool SupportsSqlType(SqlType sqlType) + { + // The Anywhere dialects define types for DbType the Anywhere driver does not support. + return sqlType.DbType switch + { + DbType.SByte => false, + _ => base.SupportsSqlType(sqlType) + }; + } } } diff --git a/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs b/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs index 87afcd89625..29a30b11bf5 100644 --- a/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs +++ b/src/NHibernate.Test/Tools/hbm2ddl/SchemaValidator/SchemaValidateTableWithSchemaFixture.cs @@ -53,7 +53,7 @@ protected override void CreateSchema() { // Unfortunateley Assert.Warn and Console.WriteLine at this place seems to be ignored in Rider // viewer. - Assert.Warn("Creating the schema failed, assuming it already exists. {0}", ex); + Assert.Warn($"Creating the schema failed, assuming it already exists. {ex}"); Console.WriteLine("Creating the schema failed, assuming it already exists."); Console.WriteLine(ex); } @@ -102,7 +102,7 @@ public void ShouldVerify() } catch (SchemaValidationException sve) { - Assert.Fail("Validation failed: {0}.\n{1}", StringHelper.CollectionToString(sve.ValidationErrors), sve); + Assert.Fail($"Validation failed: {StringHelper.CollectionToString(sve.ValidationErrors)}.\n{sve}"); } } } diff --git a/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs b/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs index c84a4e83415..00176694879 100644 --- a/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs +++ b/src/NHibernate.Test/TypeParameters/TypeParameterTest.cs @@ -71,7 +71,7 @@ public void Save() "Default value should have been mapped to null"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_TWO")) == DBNull.Value, "Default value should have been mapped to null"); - Assert.AreEqual(Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), 5, + Assert.AreEqual(5, Convert.ToInt32(reader.GetValue(reader.GetOrdinal("VALUE_THREE"))), "Non-Default value should not be changed"); Assert.IsTrue(reader.GetValue(reader.GetOrdinal("VALUE_FOUR")) == DBNull.Value, "Default value should have been mapped to null"); @@ -93,17 +93,17 @@ public void Loading() Widget obj = (Widget) s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-normal").UniqueResult(); - Assert.AreEqual(obj.ValueOne, 7, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 8, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, 9, "Non-Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, 10, "Non-Default value incorrectly loaded"); + Assert.AreEqual(7, obj.ValueOne, "Non-Default value incorrectly loaded"); + Assert.AreEqual(8, obj.ValueTwo, "Non-Default value incorrectly loaded"); + Assert.AreEqual(9, obj.ValueThree, "Non-Default value incorrectly loaded"); + Assert.AreEqual(10, obj.ValueFour, "Non-Default value incorrectly loaded"); obj = (Widget) s.CreateQuery("from Widget o where o.Str = :string") .SetString("string", "all-default").UniqueResult(); - Assert.AreEqual(obj.ValueOne, 1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueTwo, 2, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueThree, -1, "Default value incorrectly loaded"); - Assert.AreEqual(obj.ValueFour, -5, "Default value incorrectly loaded"); + Assert.AreEqual(1, obj.ValueOne, "Default value incorrectly loaded"); + Assert.AreEqual(2, obj.ValueTwo, "Default value incorrectly loaded"); + Assert.AreEqual(-1, obj.ValueThree, "Default value incorrectly loaded"); + Assert.AreEqual(-5, obj.ValueFour, "Default value incorrectly loaded"); t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs index 67b36a0d2cc..176c9954bf5 100644 --- a/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/AbstractDateTimeTypeFixture.cs @@ -28,8 +28,6 @@ public abstract class AbstractDateTimeTypeFixture : TypeFixtureBase protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; @@ -57,14 +55,10 @@ protected override void OnSetUp() protected override void OnTearDown() { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); - t.Commit(); - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete from DateTimeClass").ExecuteUpdate(); + t.Commit(); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs index cd124b00d0e..2c394a42472 100644 --- a/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/BooleanTypeFixture.cs @@ -1,3 +1,4 @@ +using System; using System.Data.Common; using NHibernate.Engine; using NHibernate.Type; @@ -69,21 +70,24 @@ public void GetByIndex(bool expected) } [Theory] + [Obsolete("Testing obsolete API")] public void GetByName(bool expected) { const string name0 = "name0"; const string name1 = "name1"; - BooleanType type = NHibernateUtil.Boolean; + var type = NHibernateUtil.Boolean; var session = Substitute.For(); var reader = Substitute.For(); - reader[name0].Returns(expected); - reader[name1].Returns(expected); + reader.GetOrdinal(name0).Returns(0); + reader.GetOrdinal(name1).Returns(1); + reader[0].Returns(expected); + reader[1].Returns(expected); var result0 = type.Get(reader, name0, session); var result1 = type.Get(reader, name1, session); - Assert.AreEqual(expected, (bool) result0); - Assert.AreSame(result0, result1); + Assert.That((bool) result0, Is.EqualTo(expected)); + Assert.That(result1, Is.SameAs(result0)); } [Test] diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs index d54f3876f33..013d98814af 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeFixture.cs @@ -28,7 +28,6 @@ protected override void Configure(Configuration configuration) ? (IType) NHibernateUtil.DateTimeNoMs : NHibernateUtil.DateTime; TypeFactory.RegisterType(typeof(DateTime), _testDefaultDateTimeType, TypeFactory.EmptyAliases); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs index e8fbd52f2db..3f9ecc0b2c6 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithLengthFixture.cs @@ -46,7 +46,6 @@ protected override void Configure(Configuration configuration) _testDefaultStringType, new[] {"string"}, length => new CustomStringType(length)); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs index 2d803f5b4e5..fd71f8da3da 100644 --- a/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs +++ b/src/NHibernate.Test/TypesTest/ChangeDefaultTypeWithPrecisionFixture.cs @@ -47,7 +47,6 @@ protected override void Configure(Configuration configuration) _testDefaultType, new[] {"currency"}, (precision, scale) => new CustomCurrencyType(precision, scale)); - base.Configure(configuration); } protected override void DropSchema() diff --git a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs index d4448ad6023..d07c2856aaa 100644 --- a/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/CharBooleanTypeFixture.cs @@ -1,4 +1,5 @@ -using System.Data.Common; +using System; +using System.Data.Common; using NHibernate.Engine; using NHibernate.SqlTypes; using NHibernate.Type; @@ -29,6 +30,7 @@ public void GetByIndex(bool expected) } [Theory] + [Obsolete("Testing obsolete API")] public void GetByName(bool value) { const string name = "0"; @@ -42,7 +44,7 @@ public void GetByName(bool value) var result = type.Get(reader, name, session); - Assert.AreSame(expected, result); + Assert.That(result, Is.SameAs(expected)); } [Theory] diff --git a/src/NHibernate.Test/TypesTest/CultureInfoClass.cs b/src/NHibernate.Test/TypesTest/CultureInfoClass.cs new file mode 100644 index 00000000000..601cf00fbda --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoClass.cs @@ -0,0 +1,12 @@ +using System; +using System.Globalization; + +namespace NHibernate.Test.TypesTest +{ + public class CultureInfoClass + { + public Guid Id { get; set; } + public CultureInfo BasicCulture { get; set; } + public CultureInfo ExtendedCulture { get; set; } + } +} diff --git a/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml b/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml new file mode 100644 index 00000000000..8472d89d7f0 --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoClass.hbm.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs b/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs new file mode 100644 index 00000000000..d860c04ba1f --- /dev/null +++ b/src/NHibernate.Test/TypesTest/CultureInfoTypeFixture.cs @@ -0,0 +1,102 @@ +using System; +using System.Globalization; +using NHibernate.Dialect; +using NHibernate.Type; +using NUnit.Framework; + +namespace NHibernate.Test.TypesTest +{ + [TestFixture] + public class CultureInfoTypeFixture : TypeFixtureBase + { + protected override string TypeName => "CultureInfo"; + + [Test] + public void ReadWriteBasicCulture() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US") }; + s.Save(entity); + id = entity.Id; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture, Is.Not.Null); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("en-US")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US"))); + entity.BasicCulture = CultureInfo.GetCultureInfo("fr-BE"); + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture.Name, Is.EqualTo("fr-BE")); + Assert.That(entity.BasicCulture, Is.EqualTo(CultureInfo.GetCultureInfo("fr-BE"))); + entity.BasicCulture = null; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.BasicCulture, Is.Null); + t.Commit(); + } + } + + [Test] + public void ReadWriteExtendedCulture() + { + Guid id; + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = new CultureInfoClass { ExtendedCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + s.Save(entity); + id = entity.Id; + t.Commit(); + } + + using (var s = OpenSession()) + using (var t = s.BeginTransaction()) + { + var entity = s.Get(id); + Assert.That(entity.ExtendedCulture, Is.Not.Null); + // Under Windows, it is named en-US-posix, but en-US-POSIX under Linux. + Assert.That(entity.ExtendedCulture.Name, Is.EqualTo("en-US-posix").IgnoreCase); + Assert.That(entity.ExtendedCulture, Is.EqualTo(CultureInfo.GetCultureInfo("en-US-posix"))); + t.Commit(); + } + } + + [Test] + public void WriteTooLongCulture() + { + if (Dialect is SQLiteDialect) + Assert.Ignore("SQLite has no length limited string type."); + using var s = OpenSession(); + using var t = s.BeginTransaction(); + var entity = new CultureInfoClass { BasicCulture = CultureInfo.GetCultureInfo("en-US-posix") }; + s.Save(entity); + Assert.That(t.Commit, Throws.Exception); + } + + [Test] + public void AutoDiscoverFromNetType() + { + // integration test to be 100% sure + var propertyType = Sfi.GetEntityPersister(typeof(CultureInfoClass).FullName).GetPropertyType(nameof(CultureInfoClass.BasicCulture)); + Assert.That(propertyType, Is.InstanceOf()); + } + } +} diff --git a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs index 0881a08e878..61a2bd59029 100644 --- a/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DateTimeOffsetTypeFixture.cs @@ -30,8 +30,6 @@ protected override bool AppliesTo(Engine.ISessionFactoryImplementor factory) => protected override void Configure(Configuration configuration) { - base.Configure(configuration); - var driverClass = ReflectHelper.ClassForName(configuration.GetProperty(Cfg.Environment.ConnectionDriver)); ClientDriverWithParamsStats.DriverClass = driverClass; @@ -57,18 +55,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DateTimeOffsetClass").ExecuteUpdate(); - t.Commit(); - } - } - protected override void DropSchema() { (Sfi.ConnectionProvider.Driver as ClientDriverWithParamsStats)?.CleanUp(); @@ -382,6 +368,14 @@ public class DateTimeOffsetTypeWithScaleFixture : DateTimeOffsetTypeFixture // The timestamp rounding in seeding does not account scale. protected override bool RevisionCheck => false; + protected override void OnTearDown() + { + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery("delete DateTimeOffsetClass").ExecuteUpdate(); + t.Commit(); + } + [Test] public void LowerDigitsAreIgnored() { diff --git a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs index 72561fc7008..7a907c84267 100644 --- a/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/DecimalTypeFixture.cs @@ -24,8 +24,6 @@ protected override bool AppliesTo(Dialect.Dialect dialect) protected override void Configure(Configuration configuration) { - base.Configure(configuration); - if (Dialect is FirebirdDialect) { configuration.SetProperty(Environment.QueryDefaultCastPrecision, "18"); @@ -45,18 +43,6 @@ protected override void OnSetUp() } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var t = s.BeginTransaction()) - { - s.CreateQuery("delete from DecimalClass").ExecuteUpdate(); - t.Commit(); - } - } - /// /// Test that two decimal fields that are exactly equal are returned /// as Equal by the DecimalType. diff --git a/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs b/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs index ca3a07797df..9574983a65b 100644 --- a/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/EnumStringTypeFixture.cs @@ -29,14 +29,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from EnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public void ReadFromLoad() { diff --git a/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs b/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs index ea64fc18a2c..1ff4f62313a 100644 --- a/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/GenericEnumStringTypeFixture.cs @@ -31,14 +31,6 @@ protected override void OnSetUp() s.Close(); } - protected override void OnTearDown() - { - ISession s = OpenSession(); - s.Delete("from GenericEnumStringClass"); - s.Flush(); - s.Close(); - } - [Test] public void ReadFromLoad() { diff --git a/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs b/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs index b87ec50892b..be2bb8e191a 100644 --- a/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/GuidTypeFixture.cs @@ -93,7 +93,7 @@ public void GuidInWhereClause() [Test] public void GetGuidWorksWhenUnderlyingTypeIsRepresentedByString() { - GuidType type = (GuidType)NHibernateUtil.Guid; + var type = NHibernateUtil.Guid; Guid value = Guid.NewGuid(); DataTable data = new DataTable("test"); @@ -106,14 +106,15 @@ public void GetGuidWorksWhenUnderlyingTypeIsRepresentedByString() var reader = data.CreateDataReader(); reader.Read(); - using (var s = OpenSession()) - { - var si = s.GetSessionImplementation(); - Assert.AreEqual(value, type.Get(reader, "guid", si)); - Assert.AreEqual(value, type.Get(reader, 0, si)); - Assert.AreEqual(value, type.Get(reader, "varchar", si)); - Assert.AreEqual(value, type.Get(reader, 1, si)); - } + using var s = OpenSession(); + var si = s.GetSessionImplementation(); + + Assert.That(type.Get(reader, 0, si), Is.EqualTo(value)); + Assert.That(type.Get(reader, 1, si), Is.EqualTo(value)); +#pragma warning disable CS0618 // Type or member is obsolete + Assert.That(type.Get(reader, "guid", si), Is.EqualTo(value)); + Assert.That(type.Get(reader, "varchar", si), Is.EqualTo(value)); +#pragma warning restore CS0618 // Type or member is obsolete } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs b/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs index 6c6e6d72cf0..f1bca0035a6 100644 --- a/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs +++ b/src/NHibernate.Test/TypesTest/SerializableTypesFixture.cs @@ -33,7 +33,7 @@ public void EachEmbeddedBasicTypeIsSerializable() foreach (var fieldInfo in builtInCustomTypes) { var ntp = (IType) fieldInfo.GetValue(null); - NHAssert.IsSerializable(ntp, fieldInfo.Name + " is not serializable"); + NHAssert.IsSerializable(ntp, $"{fieldInfo.Name} is not serializable"); } if (typeof(System.Type).IsSerializable) diff --git a/src/NHibernate.Test/TypesTest/StringTypeFixture.cs b/src/NHibernate.Test/TypesTest/StringTypeFixture.cs index e544390e5ca..7a970476cfa 100644 --- a/src/NHibernate.Test/TypesTest/StringTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/StringTypeFixture.cs @@ -14,14 +14,6 @@ protected override string TypeName get { return "String"; } } - protected override void OnTearDown() - { - using (var s = OpenSession()) - { - s.CreateQuery("delete from StringClass").ExecuteUpdate(); - } - } - [Test] public void InsertNullValue() { diff --git a/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs b/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs index 5c0e2c364f0..4684693f498 100644 --- a/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs +++ b/src/NHibernate.Test/TypesTest/TimeAsTimeSpanTypeFixture.cs @@ -38,18 +38,6 @@ protected override string TypeName get { return "TimeAsTimeSpan"; } } - protected override void OnTearDown() - { - base.OnTearDown(); - - using (var s = OpenSession()) - using (var tx = s.BeginTransaction()) - { - s.CreateQuery("delete from TimeAsTimeSpanClass").ExecuteUpdate(); - tx.Commit(); - } - } - [Test] public void PropertiesHasExpectedType() { diff --git a/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs b/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs index 3efb4bbf5b5..a11d304c69a 100644 --- a/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs +++ b/src/NHibernate.Test/TypesTest/TypeFactoryFixture.cs @@ -87,7 +87,7 @@ public void MultiThreadAccess() var errors = mtr.GetErrors(); if (errors.Length > 0) { - Assert.Fail("One or more thread failed, found {0} errors. First exception: {1}", errors.Length, errors[0]); + Assert.Fail($"One or more thread failed, found {errors.Length} errors. First exception: {errors[0]}"); } } diff --git a/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs b/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs index 048a3670b2d..6f83d6f8127 100644 --- a/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs +++ b/src/NHibernate.Test/TypesTest/TypeFixtureBase.cs @@ -1,6 +1,3 @@ -using System; -using System.Collections; - namespace NHibernate.Test.TypesTest { /// @@ -13,20 +10,16 @@ public abstract class TypeFixtureBase : TestCase { protected abstract string TypeName { get; } - protected override string MappingsAssembly - { - get { return "NHibernate.Test"; } - } + protected override string MappingsAssembly => "NHibernate.Test"; + + protected override string[] Mappings => new[] { $"TypesTest.{TypeName}Class.hbm.xml" }; - protected override string[] Mappings + protected override void OnTearDown() { - get - { - return new string[] - { - String.Format("TypesTest.{0}Class.hbm.xml", TypeName) - }; - } + using var s = OpenSession(); + using var t = s.BeginTransaction(); + s.CreateQuery($"delete {TypeName}Class").ExecuteUpdate(); + t.Commit(); } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs b/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs index 8f76ead9605..09e91e2483d 100644 --- a/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs +++ b/src/NHibernate.Test/Unionsubclass/DatabaseKeywordsFixture.cs @@ -19,8 +19,6 @@ protected override string[] Mappings protected override void Configure(Configuration configuration) { - base.Configure(configuration); - configuration.SetProperty(Environment.Hbm2ddlKeyWords, "auto-quote"); } diff --git a/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs b/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs index 8a72e49d29b..e58dad4d1cb 100644 --- a/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs +++ b/src/NHibernate.Test/Unionsubclass/UnionSubclassFixture.cs @@ -55,7 +55,7 @@ public void UnionSubclassCollection() using (ITransaction t = s.BeginTransaction()) { Human gavin = (Human)s.CreateCriteria(typeof(Human)).UniqueResult(); - Assert.AreEqual(gavin.Info.Count, 2); + Assert.AreEqual(2, gavin.Info.Count); s.Delete(gavin); s.Delete(gavin.Location); t.Commit(); diff --git a/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs b/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs index c037121dc7c..5c0cb512b27 100644 --- a/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs +++ b/src/NHibernate.Test/UtilityTest/JoinedEnumerableFixture.cs @@ -8,6 +8,8 @@ namespace NHibernate.Test.UtilityTest /// /// Test cases for the class. /// + // Since v5.6 + [Obsolete] [TestFixture] public class JoinedEnumerableFixture { diff --git a/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs b/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs new file mode 100644 index 00000000000..30002757113 --- /dev/null +++ b/src/NHibernate.Test/UtilityTest/LinkHashMapFixture.cs @@ -0,0 +1,477 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization.Formatters.Binary; +using NHibernate.Util; +using NUnit.Framework; + +namespace NHibernate.Test.UtilityTest +{ + [TestFixture] + public class LinkHashMapFixture + { + private static readonly Player[] players = + { + new Player("12341", "Boeta Dippenaar"), + new Player("23432", "Gary Kirsten"), + new Player("23411", "Graeme Smith"), + new Player("55221", "Jonty Rhodes"), + new Player("61234", "Monde Zondeki"), + new Player("23415", "Paul Adams") + }; + + private static void Fill(IDictionary lhm) + { + foreach (var player in players) + lhm.Add(player.Id, player); + } + + [Test] + public void Add() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + lhm.Add("55555", new Player("55555", "Monde Zondeki")); + + Assert.That(lhm.Count, Is.EqualTo(7)); + } + + [Test] + public void LastKeyLastValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.LastKey, Is.EqualTo(players[players.Length - 1].Id)); + Assert.That(lhm.LastValue, Is.EqualTo(players[players.Length - 1])); + + // override + var antWithSameId = new Player("12341", "Another"); + lhm[antWithSameId.Id] = antWithSameId; + Assert.That(lhm.LastKey, Is.EqualTo(antWithSameId.Id)); + Assert.That(lhm.LastValue, Is.EqualTo(antWithSameId)); + } + + [Test] + public void FirstKeyFirstValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.FirstKey, Is.EqualTo(players[0].Id)); + Assert.That(lhm.FirstValue, Is.EqualTo(players[0])); + + // override First + var antWithSameId = new Player("12341", "Another"); + lhm[antWithSameId.Id] = antWithSameId; + Assert.That(lhm.FirstKey, Is.EqualTo(players[1].Id)); + Assert.That(lhm.FirstValue, Is.EqualTo(players[1])); + } + + [Test] + public void Clear() + { + IDictionary lhm = new LinkHashMap(); + var p = new Player("78945", "Someone"); + lhm[p.Id] = p; + + lhm.Clear(); + Assert.That(lhm, Is.Empty); + + foreach (KeyValuePair pair in lhm) + Assert.Fail("Should not be any entries but found Key = " + pair.Key + " and Value = " + pair.Value); + } + + [Test] + public void Contains() + { + var lhm = new LinkHashMap(); + Fill(lhm); + + Assert.That(lhm.Contains("12341"), Is.True); + Assert.That(lhm.Contains("55555"), Is.False); + } + + [Test] + public void GetEnumerator() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + int index = 0; + foreach (KeyValuePair pair in lhm) + { + Assert.That(pair.Key, Is.EqualTo(players[index].Id)); + Assert.That(pair.Value, Is.EqualTo(players[index])); + index++; + } + + Assert.That(index, Is.EqualTo(6)); + } + + [Test] + public void GetEnumeratorEmpty() + { + IDictionary lhm = new LinkHashMap(); + Assert.That(lhm, Is.Empty); + + int entries = 0; + foreach (KeyValuePair pair in lhm) + entries++; + foreach (string s in lhm.Keys) + entries++; + foreach (Player value in lhm.Values) + entries++; + + Assert.That(entries, Is.Zero, "should not have any entries in the enumerators"); + } + + [Test] + public void GetEnumeratorModifyExceptionFromAdd() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm["78945"] = new Player("78945", "Someone"); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void GetEnumeratorModifyExceptionFromRemove() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm.Remove(pair.Key); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void GetEnumeratorModifyExceptionFromUpdate() + { + IDictionary lhm = new LinkHashMap(); + lhm["123"] = new Player("123", "yyyyyyy"); + Assert.That( + () => + { + foreach (var pair in lhm) + { + lhm["123"] = new Player("123", "aaaaaaa"); + } + }, + Throws.InvalidOperationException); + } + + [Test] + public void EnumeratorInstanceShouldNotBeNonGenericIEnumerator() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType, Is.Not.EqualTo(typeof(IEnumerator))); + } + + [Test] + public void EnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void KeysEnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.Keys.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void ValuesEnumeratorInstanceShouldBeStruct() + { + var lhm = new LinkHashMap(); + var enumerator = lhm.Values.GetEnumerator(); + var enumeratorType = enumerator.GetVariableType(); + + Assert.That(enumeratorType.IsStruct, Is.True); + } + + [Test] + public void Remove() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + + // remove an item that exists + bool removed = lhm.Remove("23411"); + Assert.That(removed, Is.True); + Assert.That(lhm.Count, Is.EqualTo(5)); + + // try to remove an item that does not exist + removed = lhm.Remove("65432"); + Assert.That(removed, Is.False); + Assert.That(lhm.Count, Is.EqualTo(5)); + } + + [Test] + public void ContainsValue() + { + var lhm = new LinkHashMap(); + Fill(lhm); + Assert.That(lhm.ContainsValue(new Player("55221", "Jonty Rhodes")), Is.True); + Assert.That(lhm.ContainsValue(new Player("55221", "SameKeyDiffName")), Is.False); + } + + [Test] + public void CopyTo() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var destArray = new KeyValuePair[lhm.Count + 1]; + destArray[0] = new KeyValuePair("999", new Player("999", "The number nine")); + lhm.CopyTo(destArray, 1); + + for (var i = 1; i < destArray.Length; i++) + { + Assert.That(destArray[i].Key, Is.EqualTo(players[i - 1].Id)); + Assert.That(destArray[i].Value, Is.EqualTo(players[i - 1])); + } + } + + [Test] + public void Keys() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var index = 0; + foreach (string s in lhm.Keys) + { + Assert.That(s, Is.EqualTo(players[index].Id)); + index++; + } + } + + [Test] + public void Values() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + var index = 0; + foreach (Player p in lhm.Values) + { + Assert.That(p, Is.EqualTo(players[index])); + index++; + } + } + + [Test] + public void Serialization() + { + IDictionary lhm = new LinkHashMap(); + Fill(lhm); + + var stream = new MemoryStream(); + var f = new BinaryFormatter + { +#if !NETFX + SurrogateSelector = new SerializationHelper.SurrogateSelector() +#endif + }; + f.Serialize(stream, lhm); + stream.Position = 0; + + var dlhm = (LinkHashMap)f.Deserialize(stream); + stream.Close(); + + Assert.That(dlhm.Count, Is.EqualTo(6)); + var index = 0; + foreach (var pair in dlhm) + { + Assert.That(pair.Key, Is.EqualTo(players[index].Id)); + Assert.That(pair.Value, Is.EqualTo(players[index])); + index++; + } + + Assert.That(index, Is.EqualTo(6)); + } + + [Test, Explicit] + public void ShowDiff() + { + IDictionary dict = new Dictionary(); + IDictionary lhm = new LinkHashMap(); + Fill(dict); + Fill(lhm); + // Override the first element + var o = new Player("12341", "Override"); + dict[o.Id] = o; + lhm[o.Id] = o; + Console.Out.WriteLine("Dictionary order:"); + foreach (KeyValuePair pair in dict) + { + Console.Out.WriteLine("Key->{0}", pair.Key); + } + Console.Out.WriteLine("LinkHashMap order:"); + foreach (KeyValuePair pair in lhm) + { + Console.Out.WriteLine("Key->{0}", pair.Key); + } + } + + [Test, Explicit] + public void Performance() + { + // Take care with this test because the result is not the same every times + + int numOfRuns = 4; + + int numOfEntries = Int16.MaxValue; + + var dictPopulateTicks = new long[numOfRuns]; + var dictItemTicks = new long[numOfRuns]; + + var linkPopulateTicks = new long[numOfRuns]; + var linkItemTicks = new long[numOfRuns]; + + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) + { + string key; + object value; + IDictionary dictionary = new Dictionary(); + IDictionary linked = new LinkHashMap(); + + long dictStart = DateTime.Now.Ticks; + + for (int i = 0; i < numOfEntries; i++) + { + dictionary.Add("test" + i, new object()); + } + + dictPopulateTicks[runIndex] = DateTime.Now.Ticks - dictStart; + + dictStart = DateTime.Now.Ticks; + for (int i = 0; i < numOfEntries; i++) + { + key = "test" + i; + value = dictionary[key]; + } + dictItemTicks[runIndex] = DateTime.Now.Ticks - dictStart; + + dictionary.Clear(); + + long linkStart = DateTime.Now.Ticks; + + for (int i = 0; i < numOfEntries; i++) + { + linked.Add("test" + i, new object()); + } + + linkPopulateTicks[runIndex] = DateTime.Now.Ticks - linkStart; + + linkStart = DateTime.Now.Ticks; + for (int i = 0; i < numOfEntries; i++) + { + key = "test" + i; + value = linked[key]; + } + + linkItemTicks[runIndex] = DateTime.Now.Ticks - linkStart; + + linked.Clear(); + } + + for (var runIndex = 0; runIndex < numOfRuns; runIndex++) + { + decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); + decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); + + string message = string.Format("LinkHashMap vs Dictionary (Run-{0}) :",runIndex+1); + message += "\n POPULATE:"; + message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; + message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; + message += "\n\t for an overhead of " + linkPopulateOverhead; + message += "\n RETRIVE:"; + message += "\n\t linked took " + linkItemTicks[runIndex] + " ticks."; + message += "\n\t dictionary took " + dictItemTicks[runIndex] + " ticks."; + message += "\n\t for an overhead of " + linkItemOverhead; + + Console.Out.WriteLine(message); + Console.Out.WriteLine(); + } + } + } + + internal static class LinkHashMapFixtureHelpers + { + public static System.Type GetVariableType(this T _) => typeof(T); + + public static bool IsStruct(this System.Type type) + { + return !type.IsClass && !type.IsInterface; + } + } + + [Serializable] + public class Player + { + private string id; + private string name; + + public Player(string id, string name) + { + if (string.IsNullOrEmpty(id)) + throw new ArgumentNullException(nameof(id)); + + if (string.IsNullOrEmpty(name)) + throw new ArgumentNullException(nameof(name)); + + this.id = id; + this.name = name; + } + + public string Id + { + get { return id; } + set { id = value; } + } + + public string Name + { + get { return name; } + set { name = value; } + } + + public override int GetHashCode() + { + return id.GetHashCode() ^ name.GetHashCode(); + } + + public override bool Equals(object obj) + { + Player that = obj as Player; + if (that == null) return false; + return id.Equals(that.id) && name.Equals(that.name); + } + + public override string ToString() + { + return $"<{id}>{name}"; + } + } +} diff --git a/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs b/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs deleted file mode 100644 index bfa995e190e..00000000000 --- a/src/NHibernate.Test/UtilityTest/LinkedHashMapFixture.cs +++ /dev/null @@ -1,415 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Runtime.Serialization.Formatters.Binary; -using NHibernate.Util; -using NUnit.Framework; - -namespace NHibernate.Test.UtilityTest -{ - [TestFixture] - public class LinkedHashMapFixture - { - private static readonly Player[] players = { - new Player("12341", "Boeta Dippenaar"), new Player("23432", "Gary Kirsten"), - new Player("23411", "Graeme Smith"), new Player("55221", "Jonty Rhodes"), - new Player("61234", "Monde Zondeki"), new Player("23415", "Paul Adams") - }; - - private static void Fill(IDictionary lhm) - { - foreach (Player player in players) - lhm.Add(player.Id, player); - } - - [Test] - public void Add() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - lhm.Add("55555", new Player("55555", "Monde Zondeki")); - - Assert.AreEqual(7, lhm.Count); - } - - [Test] - public void LastKeyLastValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.AreEqual(players[players.Length - 1].Id, lhm.LastKey); - Assert.AreEqual(players[players.Length-1], lhm.LastValue); - - // override - Player antWithSameId = new Player("12341", "Another"); - lhm[antWithSameId.Id] = antWithSameId; - Assert.AreEqual(antWithSameId.Id, lhm.LastKey); - Assert.AreEqual(antWithSameId, lhm.LastValue); - } - - [Test] - public void FirstKeyFirstValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.AreEqual(players[0].Id, lhm.FirstKey); - Assert.AreEqual(players[0], lhm.FirstValue); - - // override First - Player antWithSameId = new Player("12341", "Another"); - lhm[antWithSameId.Id] = antWithSameId; - Assert.AreEqual(players[1].Id, lhm.FirstKey); - Assert.AreEqual(players[1], lhm.FirstValue); - } - - [Test] - public void Clear() - { - IDictionary lhm = new LinkedHashMap(); - Player p = new Player("78945", "Someone"); - lhm[p.Id] = p; - - lhm.Clear(); - Assert.AreEqual(0, lhm.Count); - - foreach (KeyValuePair pair in lhm) - Assert.Fail("Should not be any entries but found Key = " + pair.Key + " and Value = " + pair.Value); - } - - [Test] - public void Contains() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - - Assert.IsTrue(lhm.Contains("12341")); - Assert.IsFalse(lhm.Contains("55555")); - } - - [Test] - public void GetEnumerator() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (KeyValuePair pair in lhm) - { - Assert.AreEqual(players[index].Id, pair.Key); - Assert.AreEqual(players[index], pair.Value); - index++; - } - - Assert.AreEqual(6, index); - } - - [Test] - public void GetEnumeratorEmpty() - { - IDictionary lhm = new LinkedHashMap(); - Assert.AreEqual(0, lhm.Count); - - int entries = 0; - foreach (KeyValuePair pair in lhm) - entries++; - foreach (string s in lhm.Keys) - entries++; - foreach (Player value in lhm.Values) - entries++; - - Assert.AreEqual(0, entries, "should not have any entries in the enumerators"); - } - - [Test] - public void GetEnumeratorModifyExceptionFromAdd() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm["78945"] = new Player("78945", "Someone"); - } - }); - } - - [Test] - public void GetEnumeratorModifyExceptionFromRemove() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm.Remove(pair.Key); - } - }); - } - - [Test] - public void GetEnumeratorModifyExceptionFromUpdate() - { - IDictionary lhm = new LinkedHashMap(); - lhm["123"] = new Player("123", "yyyyyyy"); - Assert.Throws(() => - { - foreach (KeyValuePair pair in lhm) - { - lhm["123"] = new Player("123", "aaaaaaa"); - } - }); - } - - [Test] - public void Remove() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - - // remove an item that exists - bool removed =lhm.Remove("23411"); - Assert.IsTrue(removed); - Assert.AreEqual(5, lhm.Count); - - // try to remove an item that does not exist - removed= lhm.Remove("65432"); - Assert.IsFalse(removed); - Assert.AreEqual(5, lhm.Count); - } - - [Test] - public void ContainsValue() - { - LinkedHashMap lhm = new LinkedHashMap(); - Fill(lhm); - Assert.IsTrue(lhm.ContainsValue(new Player("55221", "Jonty Rhodes"))); - Assert.IsFalse(lhm.ContainsValue(new Player("55221", "SameKeyDiffName"))); - } - - [Test] - public void CopyTo() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - KeyValuePair[] destArray = new KeyValuePair[lhm.Count + 1]; - destArray[0] = new KeyValuePair("999", new Player("999", "The number nine")); - lhm.CopyTo(destArray, 1); - - for (int i = 1; i < destArray.Length; i++) - { - Assert.AreEqual(players[i-1].Id, destArray[i].Key); - Assert.AreEqual(players[i-1], destArray[i].Value); - } - } - - [Test] - public void Keys() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (string s in lhm.Keys) - { - Assert.AreEqual(players[index].Id, s); - index++; - } - } - - [Test] - public void Values() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - int index = 0; - foreach (Player p in lhm.Values) - { - Assert.AreEqual(players[index], p); - index++; - } - } - - [Test] - public void Serialization() - { - IDictionary lhm = new LinkedHashMap(); - Fill(lhm); - - MemoryStream stream = new MemoryStream(); - var f = new BinaryFormatter - { -#if !NETFX - SurrogateSelector = new SerializationHelper.SurrogateSelector() -#endif - }; - f.Serialize(stream, lhm); - stream.Position = 0; - - LinkedHashMap dlhm = (LinkedHashMap)f.Deserialize(stream); - stream.Close(); - - Assert.AreEqual(6, dlhm.Count); - int index = 0; - foreach (KeyValuePair pair in dlhm) - { - Assert.AreEqual(players[index].Id, pair.Key); - Assert.AreEqual(players[index], pair.Value); - index++; - } - - Assert.AreEqual(6, index); - } - - [Test, Explicit] - public void ShowDiff() - { - IDictionary dict = new Dictionary(); - IDictionary lhm = new LinkedHashMap(); - Fill(dict); - Fill(lhm); - // Override the first element - Player o = new Player("12341", "Ovirride"); - dict[o.Id] = o; - lhm[o.Id] = o; - Console.Out.WriteLine("Dictionary order:"); - foreach (KeyValuePair pair in dict) - { - Console.Out.WriteLine("Key->{0}", pair.Key); - } - Console.Out.WriteLine("LinkedHashMap order:"); - foreach (KeyValuePair pair in lhm) - { - Console.Out.WriteLine("Key->{0}", pair.Key); - } - } - - [Test, Explicit] - public void Performance() - { - // Take care with this test because the result is not the same every times - - int numOfRuns = 4; - - int numOfEntries = Int16.MaxValue; - - long[] dictPopulateTicks = new long[numOfRuns]; - long[] dictItemTicks = new long[numOfRuns]; - - long[] linkPopulateTicks = new long[numOfRuns]; - long[] linkItemTicks = new long[numOfRuns]; - - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) - { - string key; - object value; - IDictionary dictionary = new Dictionary(); - IDictionary linked = new LinkedHashMap(); - - long dictStart = DateTime.Now.Ticks; - - for (int i = 0; i < numOfEntries; i++) - { - dictionary.Add("test" + i, new object()); - } - - dictPopulateTicks[runIndex] = DateTime.Now.Ticks - dictStart; - - dictStart = DateTime.Now.Ticks; - for (int i = 0; i < numOfEntries; i++) - { - key = "test" + i; - value = dictionary[key]; - } - dictItemTicks[runIndex] = DateTime.Now.Ticks - dictStart; - - dictionary.Clear(); - - long linkStart = DateTime.Now.Ticks; - - for (int i = 0; i < numOfEntries; i++) - { - linked.Add("test" + i, new object()); - } - - linkPopulateTicks[runIndex] = DateTime.Now.Ticks - linkStart; - - linkStart = DateTime.Now.Ticks; - for (int i = 0; i < numOfEntries; i++) - { - key = "test" + i; - value = linked[key]; - } - - linkItemTicks[runIndex] = DateTime.Now.Ticks - linkStart; - - linked.Clear(); - } - - for (int runIndex = 0; runIndex < numOfRuns; runIndex++) - { - decimal linkPopulateOverhead = (linkPopulateTicks[runIndex] / (decimal)dictPopulateTicks[runIndex]); - decimal linkItemOverhead = (linkItemTicks[runIndex] / (decimal)dictItemTicks[runIndex]); - - string message = string.Format("LinkedHashMap vs Dictionary (Run-{0}) :",runIndex+1); - message += "\n POPULATE:"; - message += "\n\t linked took " + linkPopulateTicks[runIndex] + " ticks."; - message += "\n\t dictionary took " + dictPopulateTicks[runIndex] + " ticks."; - message += "\n\t for an overhead of " + linkPopulateOverhead; - message += "\n RETRIVE:"; - message += "\n\t linked took " + linkItemTicks[runIndex] + " ticks."; - message += "\n\t dictionary took " + dictItemTicks[runIndex] + " ticks."; - message += "\n\t for an overhead of " + linkItemOverhead; - - Console.Out.WriteLine(message); - Console.Out.WriteLine(); - } - } - } - - [Serializable] - public class Player - { - private string id; - private string name; - public Player(string id, string name) - { - if (string.IsNullOrEmpty(id)) - throw new ArgumentNullException("id"); - - if (string.IsNullOrEmpty(name)) - throw new ArgumentNullException("name"); - - this.id = id; - this.name = name; - } - - public string Id - { - get { return id; } - set { id = value; } - } - - public string Name - { - get { return name; } - set { name = value; } - } - - public override int GetHashCode() - { - return id.GetHashCode() ^ name.GetHashCode(); - } - - public override bool Equals(object obj) - { - Player that = obj as Player; - if(that==null) return false; - return id.Equals(that.id) && name.Equals(that.name); - } - - public override string ToString() - { - return string.Format("<{0}>{1}", id, name); - } - } -} diff --git a/src/NHibernate.Test/UtilityTest/SetSnapShotFixture.cs b/src/NHibernate.Test/UtilityTest/SetSnapShotFixture.cs index e00af722111..47b03b50ec9 100644 --- a/src/NHibernate.Test/UtilityTest/SetSnapShotFixture.cs +++ b/src/NHibernate.Test/UtilityTest/SetSnapShotFixture.cs @@ -1,7 +1,10 @@ -using System.Collections.Generic; +using System; +using System.Collections; +using System.Collections.Generic; using System.IO; using System.Runtime.Serialization.Formatters.Binary; using NHibernate.Collection.Generic.SetHelpers; +using NSubstitute.ExceptionExtensions; using NUnit.Framework; namespace NHibernate.Test.UtilityTest @@ -70,6 +73,29 @@ public void TestCopyTo() Assert.That(list, Is.EquivalentTo(array)); } + [Test] + public void TestCopyToObjectArray() + { + var list = new List { "test1", null, "test2" }; + ICollection sn = new SetSnapShot(list); + + var array = new object[3]; + sn.CopyTo(array, 0); + Assert.That(list, Is.EquivalentTo(array)); + } + + [Test] + public void WhenCopyToIsCalledWithIncompatibleArrayTypeThenThrowArgumentOrInvalidCastException() + { + var list = new List { "test1", null, "test2" }; + ICollection sn = new SetSnapShot(list); + + var array = new int[3]; + Assert.That( + () => sn.CopyTo(array, 0), + Throws.ArgumentException.Or.TypeOf()); + } + [Test] public void TestSerialization() { diff --git a/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs b/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs index c5c50b96ab8..7e22a859145 100644 --- a/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs +++ b/src/NHibernate.Test/VersionTest/Db/DbVersionFixture.cs @@ -42,6 +42,7 @@ public void CollectionVersion() admin = s.Get(admin.Id); guy.Groups.Add(admin); admin.Users.Add(guy); + guy.NoOptimisticLock = "changed"; t.Commit(); s.Close(); diff --git a/src/NHibernate.Test/VersionTest/Db/User.cs b/src/NHibernate.Test/VersionTest/Db/User.cs index 6dc9368c55f..ad0aafb833b 100644 --- a/src/NHibernate.Test/VersionTest/Db/User.cs +++ b/src/NHibernate.Test/VersionTest/Db/User.cs @@ -11,8 +11,10 @@ public class User public virtual string Username { get; set; } + public virtual string NoOptimisticLock { get; set; } + public virtual ISet Groups { get; set; } public virtual ISet Permissions { get; set; } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/VersionTest/Db/User.hbm.xml b/src/NHibernate.Test/VersionTest/Db/User.hbm.xml index b809ccc8c72..1dfc4080a07 100644 --- a/src/NHibernate.Test/VersionTest/Db/User.hbm.xml +++ b/src/NHibernate.Test/VersionTest/Db/User.hbm.xml @@ -1,4 +1,4 @@ - + + + + diff --git a/src/NHibernate/NonUniqueObjectException.cs b/src/NHibernate/NonUniqueObjectException.cs index ba7f60e4ffc..ba695cb8bb0 100644 --- a/src/NHibernate/NonUniqueObjectException.cs +++ b/src/NHibernate/NonUniqueObjectException.cs @@ -61,13 +61,15 @@ public string EntityName /// /// Initializes a new instance of the class. /// - protected NonUniqueObjectException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected NonUniqueObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { identifier = info.GetValue("identifier", typeof(Object)); entityName = info.GetValue("entityName", typeof(string)) as string; } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -79,6 +81,8 @@ protected NonUniqueObjectException(SerializationInfo info, StreamingContext cont /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -86,6 +90,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("identifier", identifier, typeof(Object)); info.AddValue("entityName", entityName, typeof(string)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/NonUniqueResultException.cs b/src/NHibernate/NonUniqueResultException.cs index 82ff46f6de5..81038d8e157 100644 --- a/src/NHibernate/NonUniqueResultException.cs +++ b/src/NHibernate/NonUniqueResultException.cs @@ -32,8 +32,9 @@ public NonUniqueResultException(int resultCount) /// /// The that contains contextual information about the source or destination. /// - protected NonUniqueResultException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected NonUniqueResultException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/ObjectDeletedException.cs b/src/NHibernate/ObjectDeletedException.cs index c3ee6a853c6..b763a97ba92 100644 --- a/src/NHibernate/ObjectDeletedException.cs +++ b/src/NHibernate/ObjectDeletedException.cs @@ -30,10 +30,12 @@ public ObjectDeletedException(string message, object identifier, string clazz) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ObjectDeletedException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs b/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs index f61442aaefc..9ffb72c47f3 100644 --- a/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs +++ b/src/NHibernate/ObjectNotFoundByUniqueKeyException.cs @@ -36,13 +36,17 @@ public ObjectNotFoundByUniqueKeyException(string entityName, string propertyName #region Serialization - protected ObjectNotFoundByUniqueKeyException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected ObjectNotFoundByUniqueKeyException(SerializationInfo info, StreamingContext context) : base(info, context) { Key = info.GetValue(nameof(Key), typeof(object)); PropertyName = info.GetString(nameof(PropertyName)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -50,6 +54,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue(nameof(Key), Key); info.AddValue(nameof(PropertyName), PropertyName); } +#pragma warning restore CS0809 #endregion Serialization } diff --git a/src/NHibernate/ObjectNotFoundException.cs b/src/NHibernate/ObjectNotFoundException.cs index d09447b44b8..71fb3705c4e 100644 --- a/src/NHibernate/ObjectNotFoundException.cs +++ b/src/NHibernate/ObjectNotFoundException.cs @@ -38,10 +38,12 @@ public ObjectNotFoundException(object identifier, string entityName) : base(iden /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ObjectNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { } #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/PersistentObjectException.cs b/src/NHibernate/PersistentObjectException.cs index 0a3d7cc7563..e6384138424 100644 --- a/src/NHibernate/PersistentObjectException.cs +++ b/src/NHibernate/PersistentObjectException.cs @@ -29,8 +29,10 @@ public PersistentObjectException(string message) : base(message) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected PersistentObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs index b561db2f36e..a5c18cf92cb 100644 --- a/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/AbstractCollectionPersister.cs @@ -1503,10 +1503,16 @@ protected virtual string FilterFragment(string alias) public virtual string FilterFragment(string alias, IDictionary enabledFilters) { + var filterFragment = FilterFragment(alias); + if (!filterHelper.IsAffectedBy(enabledFilters)) + return filterFragment; + + if (ElementType.IsEntityType && elementPersister is AbstractEntityPersister ep) + return ep.FilterFragment(filterHelper, alias, enabledFilters, filterFragment); + StringBuilder sessionFilterFragment = new StringBuilder(); filterHelper.Render(sessionFilterFragment, alias, enabledFilters); - - return sessionFilterFragment.Append(FilterFragment(alias)).ToString(); + return sessionFilterFragment.Append(filterFragment).ToString(); } public string OneToManyFilterFragment(string alias) @@ -1771,8 +1777,15 @@ public virtual string SelectFragment( return SelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = true}); } - //6.0 TODO: Make abstract + // 6.0 TODO: Remove + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public virtual string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string currentCollectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, currentCollectionSuffix, includeCollectionColumns, entityInfo); + } + + // 6.0 TODO: Make abstract + public virtual string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { throw new NotImplementedException("SelectFragment with fetching lazy properties option is not implemented by " + GetType().FullName); } diff --git a/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs b/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs index 65eb87b0724..d28a1a5b7ee 100644 --- a/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs +++ b/src/NHibernate/Persister/Collection/BasicCollectionPersister.cs @@ -262,51 +262,15 @@ protected override int DoUpdateRows(object id, IPersistentCollection collection, } } + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { - // we need to determine the best way to know that two joinables - // represent a single many-to-many... - if (rhs != null && IsManyToMany && !rhs.IsCollection) - { - IAssociationType elementType = (IAssociationType) ElementType; - if (rhs.Equals(elementType.GetAssociatedJoinable(Factory))) - { - return ManyToManySelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, elementType); - } - } - return includeCollectionColumns - ? GetSelectFragment(lhsAlias, collectionSuffix).ToSqlStringFragment(false) - : string.Empty; + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); } - private string ManyToManySelectFragment( - IJoinable rhs, - string rhsAlias, - string lhsAlias, - string collectionSuffix, - IAssociationType elementType) + public override string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { - SelectFragment frag = GenerateSelectFragment(lhsAlias, collectionSuffix); - - // We need to select in the associated entity table instead of taking the collection actual element, - // because filters can be applied to the entity table outer join. In such case, we need to return null - // for filtered-out elements. (It is tempting to switch to an inner join and just use - // SelectFragment(lhsAlias, collectionSuffix) for many-to-many too, but this would hinder the proper - // handling of the not-found feature.) - var elementColumnNames = string.IsNullOrEmpty(elementType.RHSUniqueKeyPropertyName) - ? rhs.KeyColumnNames - // rhs is the entity persister, it does not handle being referenced through an unique key by a - // collection and always yield its identifier columns as KeyColumnNames. We need to resolve the - // key columns instead. - // 6.0 TODO: consider breaking again that IJoinable.SelectFragment interface for transmitting - // the OuterJoinableAssociation instead of its Joinable property. This would allow to get the - // adequate columns directly instead of re-computing them. - : ((IPropertyMapping) rhs).ToColumns(elementType.RHSUniqueKeyPropertyName); - frag.AddColumns(rhsAlias, elementColumnNames, elementColumnAliases); - AppendIndexColumns(frag, lhsAlias); - AppendIdentifierColumns(frag, lhsAlias); - - return frag.ToSqlStringFragment(false); + return includeCollectionColumns ? GetSelectFragment(lhsAlias, collectionSuffix).ToSqlStringFragment(false) : string.Empty; } /// diff --git a/src/NHibernate/Persister/Collection/OneToManyPersister.cs b/src/NHibernate/Persister/Collection/OneToManyPersister.cs index 2973deec937..2f525fe65f0 100644 --- a/src/NHibernate/Persister/Collection/OneToManyPersister.cs +++ b/src/NHibernate/Persister/Collection/OneToManyPersister.cs @@ -294,7 +294,13 @@ protected override int DoUpdateRows(object id, IPersistentCollection collection, } } + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); + } + + public override string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { var buf = new StringBuilder(); @@ -317,7 +323,7 @@ public override string SelectFragment(IJoinable rhs, string rhsAlias, string lhs { var selectMode = ReflectHelper.CastOrThrow(ElementPersister, "fetch lazy properties"); if (selectMode != null) - return buf.Append(selectMode.SelectFragment(null, null, lhsAlias, null, false, entityInfo)).ToString(); + return buf.Append(selectMode.SelectFragment(lhsAlias, null, false, entityInfo)).ToString(); } var ojl = (IOuterJoinLoadable)ElementPersister; diff --git a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs index 09fb7407278..77729249b62 100644 --- a/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/AbstractEntityPersister.cs @@ -263,7 +263,7 @@ public virtual void BindValues(DbCommand ps) // This must be a Lazy, because instances of this class must be thread safe. private readonly Lazy defaultUniqueKeyPropertyNamesForSelectId; - private readonly Dictionary propertyTableNumbersByNameAndSubclass = new Dictionary(); + private readonly Dictionary propertySubclassJoinTableNumbersByName; protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurrencyStrategy cache, ISessionFactoryImplementor factory) @@ -441,6 +441,17 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr List columnSelectables = new List(); List propNullables = new List(); + if (persistentClass.SubclassJoinClosureIterator.Any()) + { + propertySubclassJoinTableNumbersByName = new Dictionary(); + foreach (Property prop in persistentClass.SubclassPropertyClosureIterator) + { + var joinNumber = persistentClass.GetJoinNumber(prop); + if (joinNumber != 0) + propertySubclassJoinTableNumbersByName[prop.PersistentClass.EntityName + '.' + prop.Name] = joinNumber; + } + } + foreach (Property prop in persistentClass.SubclassPropertyClosureIterator) { names.Add(prop.Name); @@ -449,8 +460,6 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr definedBySubclass.Add(isDefinedBySubclass); propNullables.Add(prop.IsOptional || isDefinedBySubclass); //TODO: is this completely correct? types.Add(prop.Type); - propertyTableNumbersByNameAndSubclass[prop.PersistentClass.EntityName + '.' + prop.Name] = - persistentClass.GetJoinNumber(prop); string[] cols = new string[prop.ColumnSpan]; string[] forms = new string[prop.ColumnSpan]; @@ -1125,12 +1134,15 @@ protected virtual bool IsIdOfTable(int property, int table) protected abstract int GetSubclassPropertyTableNumber(int i); - internal int GetSubclassPropertyTableNumber(string propertyName, string entityName) + internal int GetSubclassJoinPropertyTableNumber(string propertyName, string entityName) { + if (propertySubclassJoinTableNumbersByName == null) + return 0; + var type = propertyMapping.ToType(propertyName); if (type.IsAssociationType && ((IAssociationType) type).UseLHSPrimaryKey) return 0; - propertyTableNumbersByNameAndSubclass.TryGetValue(entityName + '.' + propertyName, out var tabnum); + propertySubclassJoinTableNumbersByName.TryGetValue(entityName + '.' + propertyName, out var tabnum); return tabnum; } @@ -2364,14 +2376,14 @@ protected void InitSubclassPropertyAliasesMap(PersistentClass model) { if (entityMetamodel.HasNonIdentifierPropertyNamedId) { - subclassPropertyAliases[EntityPersister.EntityID + "." + idPropertyNames[i]] = new string[] { idAliases[i] }; - subclassPropertyColumnNames[EntityPersister.EntityID + "." + IdentifierPropertyName + "." + idPropertyNames[i]] = new string[] { idColumnNames[i] }; + subclassPropertyAliases[string.Intern(EntityPersister.EntityID + "." + idPropertyNames[i])] = new string[] { idAliases[i] }; + subclassPropertyColumnNames[string.Intern(EntityPersister.EntityID + "." + IdentifierPropertyName + "." + idPropertyNames[i])] = new string[] { idColumnNames[i] }; } // if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) { if (HasIdentifierProperty) { - subclassPropertyAliases[IdentifierPropertyName + "." + idPropertyNames[i]] = new string[] { idAliases[i] }; - subclassPropertyColumnNames[IdentifierPropertyName + "." + idPropertyNames[i]] = new string[] { idColumnNames[i] }; + subclassPropertyAliases[string.Intern(IdentifierPropertyName + "." + idPropertyNames[i])] = new string[] { idAliases[i] }; + subclassPropertyColumnNames[string.Intern(IdentifierPropertyName + "." + idPropertyNames[i])] = new string[] { idColumnNames[i] }; } else { @@ -3729,6 +3741,12 @@ public virtual string FilterFragment(string alias, IDictionary if (!filterHelper.IsAffectedBy(enabledFilters)) return filterFragment; + return FilterFragment(filterHelper, alias, enabledFilters, filterFragment); + } + + //TODO 6.0: Move to IEntityPersister and adjust usages accordingly + public virtual string FilterFragment(FilterHelper filterHelper, string alias, IDictionary enabledFilters, string filterFragment) + { var sessionFilterFragment = new StringBuilder(); filterHelper.Render(sessionFilterFragment, GenerateFilterConditionAlias(alias), GetColumnsToTableAliasMap(alias), enabledFilters); return sessionFilterFragment.Append(filterFragment).ToString(); @@ -4443,10 +4461,17 @@ public string SelectFragment( IJoinable rhs, string rhsAlias, string lhsAlias, string entitySuffix, string collectionSuffix, bool includeCollectionColumns, bool includeLazyProperties) { - return SelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = includeLazyProperties}); + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, new EntityLoadInfo(entitySuffix) {IncludeLazyProps = includeLazyProperties}); } + //Since v5.5 + [Obsolete("Please use overload without rhs and rhsAlias parameters")] public string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) + { + return SelectFragment(lhsAlias, collectionSuffix, includeCollectionColumns, entityInfo); + } + + public string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo) { return GetIdentifierSelectFragment(lhsAlias, entityInfo.EntitySuffix).ToSqlStringFragment(false) + GetPropertiesSelectFragment( @@ -4872,7 +4897,7 @@ internal SqlString GenerateSequentialSelect(AbstractEntityPersister subclassPers var classes = subclassPersister.PropertySubclassNames; for (var i = 0; i < props.Length; i++) { - var propTableNumber = GetSubclassPropertyTableNumber(props[i], classes[i]); + var propTableNumber = GetSubclassJoinPropertyTableNumber(props[i], classes[i]); if (IsSubclassTableSequentialSelect(propTableNumber) && !IsSubclassTableLazy(propTableNumber)) { tableNumbers.Add(propTableNumber); diff --git a/src/NHibernate/Persister/Entity/AbstractPropertyMapping.cs b/src/NHibernate/Persister/Entity/AbstractPropertyMapping.cs index c027568bf18..21a47e59d9c 100644 --- a/src/NHibernate/Persister/Entity/AbstractPropertyMapping.cs +++ b/src/NHibernate/Persister/Entity/AbstractPropertyMapping.cs @@ -211,7 +211,7 @@ private static string ExtendPath(string path, string property) if (string.IsNullOrEmpty(path)) return property; - return StringHelper.Qualify(path, property); + return string.Intern(StringHelper.Qualify(path, property)); } public string[] GetColumnNames(string propertyName) diff --git a/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs b/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs index bff0512d40f..45ddb1d2123 100644 --- a/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs +++ b/src/NHibernate/Persister/Entity/ISupportSelectModeJoinable.cs @@ -36,6 +36,6 @@ public EntityLoadInfo(string entitySuffix) // 6.0 TODO: merge into 'IJoinable'. internal interface ISupportLazyPropsJoinable { - string SelectFragment(IJoinable rhs, string rhsAlias, string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo); + string SelectFragment(string lhsAlias, string collectionSuffix, bool includeCollectionColumns, EntityLoadInfo entityInfo); } } diff --git a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs index 9aa8a71a3e4..3b1f0c5f7a8 100644 --- a/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs +++ b/src/NHibernate/Persister/Entity/SingleTableEntityPersister.cs @@ -696,7 +696,7 @@ protected override void AddDiscriminatorToInsert(SqlInsertBuilder insert) protected override bool IsSubclassPropertyDeferred(string propertyName, string entityName) { return - hasSequentialSelects && IsSubclassTableSequentialSelect(base.GetSubclassPropertyTableNumber(propertyName, entityName)); + hasSequentialSelects && IsSubclassTableSequentialSelect(GetSubclassPropertyTableNumber(propertyName, entityName)); } protected override bool IsPropertyDeferred(int propertyIndex) @@ -713,9 +713,9 @@ public override bool HasSequentialSelect //Since v5.3 [Obsolete("This method has no more usage in NHibernate and will be removed in a future version.")] - public new int GetSubclassPropertyTableNumber(string propertyName, string entityName) + public int GetSubclassPropertyTableNumber(string propertyName, string entityName) { - return base.GetSubclassPropertyTableNumber(propertyName, entityName); + return GetSubclassJoinPropertyTableNumber(propertyName, entityName); } //Since v5.3 diff --git a/src/NHibernate/PropertyAccessException.cs b/src/NHibernate/PropertyAccessException.cs index 47666cd249a..66f9608698d 100644 --- a/src/NHibernate/PropertyAccessException.cs +++ b/src/NHibernate/PropertyAccessException.cs @@ -81,6 +81,8 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected PropertyAccessException(SerializationInfo info, StreamingContext context) : base(info, context) { persistentType = info.GetValue("persistentType", typeof(System.Type)) as System.Type; @@ -88,6 +90,7 @@ protected PropertyAccessException(SerializationInfo info, StreamingContext conte wasSetter = info.GetBoolean("wasSetter"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -99,6 +102,8 @@ protected PropertyAccessException(SerializationInfo info, StreamingContext conte /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -107,7 +112,8 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("propertyName", propertyName); info.AddValue("wasSetter", wasSetter); } +#pragma warning restore CS0809 #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/PropertyNotFoundException.cs b/src/NHibernate/PropertyNotFoundException.cs index d64108eaae3..3a13d5eb256 100644 --- a/src/NHibernate/PropertyNotFoundException.cs +++ b/src/NHibernate/PropertyNotFoundException.cs @@ -59,8 +59,9 @@ public PropertyNotFoundException(string propertyName, string fieldName, System.T /// /// The that contains contextual information about the source or destination. /// - protected PropertyNotFoundException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected PropertyNotFoundException(SerializationInfo info, StreamingContext context) : base(info, context) { foreach (var entry in info) { @@ -81,6 +82,9 @@ protected PropertyNotFoundException(SerializationInfo info, StreamingContext con } } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -89,6 +93,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("PropertyName", PropertyName); info.AddValue("AccessorType", AccessorType); } +#pragma warning restore CS0809 public System.Type TargetType { get; } diff --git a/src/NHibernate/PropertyValueException.cs b/src/NHibernate/PropertyValueException.cs index c58d57ed75f..fe62bd72b83 100644 --- a/src/NHibernate/PropertyValueException.cs +++ b/src/NHibernate/PropertyValueException.cs @@ -64,13 +64,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// - protected PropertyValueException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected PropertyValueException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; propertyName = info.GetString("propertyName"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -82,6 +84,8 @@ protected PropertyValueException(SerializationInfo info, StreamingContext contex /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -89,6 +93,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName); info.AddValue("propertyName", propertyName); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs b/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs index 052833230fe..f57cf3fe287 100644 --- a/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs +++ b/src/NHibernate/Proxy/DefaultDynamicProxyMethodCheckerExtensions.cs @@ -11,7 +11,7 @@ public static bool IsProxiable(this MethodInfo method) { return !method.IsFinal && (method.DeclaringType != typeof(MarshalByRefObject)) - && (method.DeclaringType != typeof(object) || !"finalize".Equals(method.Name, StringComparison.OrdinalIgnoreCase)) + && !IsFinalizeMethod(method) && ( ((method.IsPublic || method.IsFamily) && (method.IsVirtual || method.IsAbstract)) // public or protected (virtual) @@ -23,22 +23,18 @@ public static bool IsProxiable(this MethodInfo method) public static bool ShouldBeProxiable(this MethodInfo method) { // to use only for real methods (no getter/setter) - return (method.DeclaringType != typeof (MarshalByRefObject)) && - (method.DeclaringType != typeof (object) || !"finalize".Equals(method.Name, StringComparison.OrdinalIgnoreCase)) && - (!(method.DeclaringType == typeof (object) && "GetType".Equals(method.Name))) && - (!(method.DeclaringType == typeof (object) && "obj_address".Equals(method.Name))) && // Mono-specific method + return method.DeclaringType != typeof(MarshalByRefObject) && + !(method.DeclaringType == typeof(object) && !method.IsVirtual) && !IsDisposeMethod(method) && - (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly); + (method.IsPublic || method.IsAssembly || method.IsFamilyOrAssembly); } public static bool ShouldBeProxiable(this PropertyInfo propertyInfo) { - if(propertyInfo != null) - { - var accessors = propertyInfo.GetAccessors(true); - return accessors.Where(x => x.IsPublic || x.IsAssembly || x.IsFamilyOrAssembly).Any(); - } - return true; + if (propertyInfo == null) return true; + + var accessors = propertyInfo.GetAccessors(true); + return accessors.Any(x => x.IsPublic || x.IsAssembly || x.IsFamilyOrAssembly); } private static bool IsDisposeMethod(MethodInfo method) @@ -47,5 +43,10 @@ private static bool IsDisposeMethod(MethodInfo method) return method.Name.Equals("Dispose") && method.MemberType == MemberTypes.Method && method.GetParameters().Length == 0; // return method.Name.Equals("Dispose") && method.IsMethodOf(typeof(IDisposable)); } + + private static bool IsFinalizeMethod(MethodInfo method) + { + return method.GetBaseDefinition() == ReflectionCache.ObjectMethods.Finalize; + } } } diff --git a/src/NHibernate/Proxy/DynProxyTypeValidator.cs b/src/NHibernate/Proxy/DynProxyTypeValidator.cs index 2f0370c3628..b53df86c5b6 100644 --- a/src/NHibernate/Proxy/DynProxyTypeValidator.cs +++ b/src/NHibernate/Proxy/DynProxyTypeValidator.cs @@ -50,9 +50,8 @@ protected virtual void CheckAccessibleMembersAreVirtual(System.Type type) foreach (var member in members) { - if (member is PropertyInfo) + if (member is PropertyInfo property) { - var property = (PropertyInfo) member; if(property.ShouldBeProxiable()) { MethodInfo[] accessors = property.GetAccessors(true); @@ -66,21 +65,19 @@ protected virtual void CheckAccessibleMembersAreVirtual(System.Type type) } } } - else if (member is MethodInfo) + else if (member is MethodInfo method) { - var methodInfo = (MethodInfo) member; // avoid the check of properties getter and setter because already checked when the PropertyInfo was found. - if (!IsPropertyMethod(methodInfo) && methodInfo.ShouldBeProxiable()) + if (!IsPropertyMethod(method) && method.ShouldBeProxiable()) { - CheckMethodIsVirtual(type, methodInfo); + CheckMethodIsVirtual(type, method); } } - else if (member is FieldInfo) + else if (member is FieldInfo field) { - var memberField = (FieldInfo) member; - if (memberField.IsPublic || memberField.IsAssembly || memberField.IsFamilyOrAssembly) + if (field.IsPublic || field.IsAssembly || field.IsFamilyOrAssembly) { - EnlistError(type, "field " + member.Name + " should not be public nor internal (ecapsulate it in a property)."); + EnlistError(type, "field " + field.Name + " should not be public nor internal (ecapsulate it in a property)."); } } } diff --git a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs index 9e1326c3b2a..4fed7814108 100644 --- a/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs +++ b/src/NHibernate/Proxy/FieldInterceptorProxyBuilder.cs @@ -57,10 +57,9 @@ public static TypeInfo CreateProxyType(System.Type baseType) var assemblyBuilder = ProxyBuilderHelper.DefineDynamicAssembly(AppDomain.CurrentDomain, name); -#if NETFX || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_1_OR_GREATER if (!baseType.IsVisible) ProxyBuilderHelper.GenerateInstanceOfIgnoresAccessChecksToAttribute(assemblyBuilder, baseType.Assembly.GetName().Name); -#endif + var moduleBuilder = ProxyBuilderHelper.DefineDynamicModule(assemblyBuilder, moduleName); const TypeAttributes typeAttributes = TypeAttributes.AutoClass | TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.BeforeFieldInit; @@ -94,11 +93,11 @@ public static TypeInfo CreateProxyType(System.Type baseType) private static void CreateProxiedMethod(TypeBuilder typeBuilder, MethodInfo method, FieldInfo fieldInterceptorField) { - if (ReflectHelper.IsPropertyGet(method)) + if (ReflectHelper.IsPropertyGet(method) && method.GetParameters().Length == 0) { ImplementGet(typeBuilder, method, fieldInterceptorField); } - else if (ReflectHelper.IsPropertySet(method)) + else if (ReflectHelper.IsPropertySet(method) && method.GetParameters().Length == 1) { ImplementSet(typeBuilder, method, fieldInterceptorField); } diff --git a/src/NHibernate/Proxy/ProxyBuilderHelper.cs b/src/NHibernate/Proxy/ProxyBuilderHelper.cs index 64ee3879e67..7f922911616 100644 --- a/src/NHibernate/Proxy/ProxyBuilderHelper.cs +++ b/src/NHibernate/Proxy/ProxyBuilderHelper.cs @@ -21,6 +21,8 @@ namespace NHibernate.Proxy { internal static class ProxyBuilderHelper { + private const BindingFlags ProxiableMethodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + private static readonly ConstructorInfo ObjectConstructor = typeof(object).GetConstructor(System.Type.EmptyTypes); private static readonly ConstructorInfo SecurityCriticalAttributeConstructor = typeof(SecurityCriticalAttribute).GetConstructor(System.Type.EmptyTypes); private static readonly ConstructorInfo IgnoresAccessChecksToAttributeConstructor = typeof(IgnoresAccessChecksToAttribute).GetConstructor(new[] {typeof(string)}); @@ -94,10 +96,7 @@ internal static void CallDefaultBaseConstructor(ILGenerator il, System.Type pare internal static IEnumerable GetProxiableMethods(System.Type type) { - const BindingFlags candidateMethodsBindingFlags = - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; - - return type.GetMethods(candidateMethodsBindingFlags).Where(m => m.IsProxiable()); + return type.GetMethods(ProxiableMethodsBindingFlags).Where(m => m.IsProxiable()); } internal static IEnumerable GetProxiableMethods(System.Type type, IEnumerable interfaces) @@ -105,12 +104,12 @@ internal static IEnumerable GetProxiableMethods(System.Type type, IE if (type.IsInterface || type == typeof(object) || type.GetInterfaces().Length == 0) { return GetProxiableMethods(type) - .Concat(interfaces.SelectMany(i => i.GetMethods())) + .Concat(interfaces.SelectMany(i => i.GetMethods(ProxiableMethodsBindingFlags))) .Distinct(); } var proxiableMethods = new HashSet(GetProxiableMethods(type), new MethodInfoComparer(type)); - foreach (var interfaceMethod in interfaces.SelectMany(i => i.GetMethods())) + foreach (var interfaceMethod in interfaces.SelectMany(i => i.GetMethods(ProxiableMethodsBindingFlags))) { proxiableMethods.Add(interfaceMethod); } diff --git a/src/NHibernate/QueryException.cs b/src/NHibernate/QueryException.cs index ff16cad0489..e26275d950e 100644 --- a/src/NHibernate/QueryException.cs +++ b/src/NHibernate/QueryException.cs @@ -112,11 +112,14 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QueryException(SerializationInfo info, StreamingContext context) : base(info, context) { queryString = info.GetString("queryString"); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -128,12 +131,15 @@ protected QueryException(SerializationInfo info, StreamingContext context) : bas /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("queryString", queryString, typeof(String)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/QueryParameterException.cs b/src/NHibernate/QueryParameterException.cs index 959ab847de4..7948b0549b1 100644 --- a/src/NHibernate/QueryParameterException.cs +++ b/src/NHibernate/QueryParameterException.cs @@ -9,6 +9,8 @@ public class QueryParameterException : QueryException // TODO : without default constructor can't be serialized public QueryParameterException(string message) : base(message) { } public QueryParameterException(string message, Exception inner) : base(message, inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected QueryParameterException(SerializationInfo info,StreamingContext context): base(info, context) { } } } diff --git a/src/NHibernate/SchemaValidationException.cs b/src/NHibernate/SchemaValidationException.cs index 2d654a07583..fdb2d0bc1b6 100644 --- a/src/NHibernate/SchemaValidationException.cs +++ b/src/NHibernate/SchemaValidationException.cs @@ -16,17 +16,23 @@ public SchemaValidationException(string msg, IList validationErrors) : b ValidationErrors = new ReadOnlyCollection(validationErrors); } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SchemaValidationException(SerializationInfo info, StreamingContext context) : base(info, context) { ValidationErrors = (ReadOnlyCollection) info.GetValue("ValidationErrors", typeof(ReadOnlyCollection)); } +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); info.AddValue("ValidationErrors", ValidationErrors); } +#pragma warning restore CS0809 } } diff --git a/src/NHibernate/SessionException.cs b/src/NHibernate/SessionException.cs index 96ce8ccc697..0c082fcb9ce 100644 --- a/src/NHibernate/SessionException.cs +++ b/src/NHibernate/SessionException.cs @@ -11,8 +11,9 @@ public SessionException(string message) { } - protected SessionException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected SessionException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/SqlCommand/CaseFragment.cs b/src/NHibernate/SqlCommand/CaseFragment.cs index 5a4a0ff3c1f..a7d1240cc60 100644 --- a/src/NHibernate/SqlCommand/CaseFragment.cs +++ b/src/NHibernate/SqlCommand/CaseFragment.cs @@ -9,7 +9,7 @@ public abstract class CaseFragment protected internal readonly Dialect.Dialect dialect; protected internal string returnColumnName; - protected internal IDictionary cases = new LinkedHashMap(); + protected internal IDictionary cases = new LinkHashMap(); protected CaseFragment(Dialect.Dialect dialect) { @@ -35,4 +35,4 @@ public virtual CaseFragment AddWhenColumnNotNull(string alias, string columnName public abstract string ToSqlStringFragment(); } -} \ No newline at end of file +} diff --git a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs index d73f98fd4d5..d71774848b9 100644 --- a/src/NHibernate/SqlCommand/SqlInsertBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlInsertBuilder.cs @@ -19,7 +19,7 @@ public class SqlInsertBuilder : ISqlStringBuilder private string comment; // columns-> (ColumnName, Value) or (ColumnName, SqlType) for parametrized column - private readonly LinkedHashMap columns = new LinkedHashMap(); + private readonly LinkHashMap columns = new(); public SqlInsertBuilder(ISessionFactoryImplementor factory) { @@ -66,6 +66,8 @@ public virtual SqlInsertBuilder AddColumn(string columnName, IType propertyType) /// The value to set for the column. /// The NHibernateType to use to convert the value to a sql string. /// The SqlInsertBuilder. + // Since v5.6 + [Obsolete("This method is unsafe and has no more usages. Use the overload with a property type and use a parameterized query.")] public SqlInsertBuilder AddColumn(string columnName, object val, ILiteralType literalType) { return AddColumn(columnName, literalType.ObjectToSQLString(val, Dialect)); diff --git a/src/NHibernate/SqlCommand/SqlString.cs b/src/NHibernate/SqlCommand/SqlString.cs index 311f8a06ef0..8f5a1656382 100644 --- a/src/NHibernate/SqlCommand/SqlString.cs +++ b/src/NHibernate/SqlCommand/SqlString.cs @@ -215,6 +215,9 @@ internal SqlString(IEnumerable parts) _firstPartIndex = _parts.Count > 0 ? 0 : -1; _lastPartIndex = _parts.Count - 1; _length = sqlIndex; + + _parts.TrimExcess(); + _parameters.TrimExcess(); } #endregion @@ -702,6 +705,10 @@ public SqlString Trim() if (_firstPartIndex < 0) return this; GetTrimmedIndexes(out var sqlStartIndex, out var length); + + if (_sqlStartIndex == sqlStartIndex && _length == length) + return this; + return length > 0 ? new SqlString(this, sqlStartIndex, length) : Empty; diff --git a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs index c9b7ccd1352..cb4d316961d 100644 --- a/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs +++ b/src/NHibernate/SqlCommand/SqlUpdateBuilder.cs @@ -19,7 +19,7 @@ public class SqlUpdateBuilder : SqlBaseBuilder, ISqlStringBuilder private string comment; // columns-> (ColumnName, Value) or (ColumnName, SqlType) for parametrized column - private readonly LinkedHashMap columns = new LinkedHashMap(); + private readonly LinkHashMap columns = new(); private List whereStrings = new List(); private readonly List whereParameterTypes = new List(); @@ -47,6 +47,8 @@ public SqlUpdateBuilder SetComment(string comment) /// The value to set for the column. /// The NHibernateType to use to convert the value to a sql string. /// The SqlUpdateBuilder. + // Since v5.6 + [Obsolete("This method is unsafe and has no more usages. Use the overload with a property type and use a parameterized query.")] public SqlUpdateBuilder AddColumn(string columnName, object val, ILiteralType literalType) { return AddColumn(columnName, literalType.ObjectToSQLString(val, Dialect)); diff --git a/src/NHibernate/SqlTypes/SqlType.cs b/src/NHibernate/SqlTypes/SqlType.cs index 29523e9122e..0aca2e81921 100644 --- a/src/NHibernate/SqlTypes/SqlType.cs +++ b/src/NHibernate/SqlTypes/SqlType.cs @@ -23,71 +23,45 @@ namespace NHibernate.SqlTypes [Serializable] public class SqlType : IEquatable { - private readonly DbType dbType; - private readonly int length; - private readonly byte precision; - private readonly byte scale; - private readonly bool lengthDefined; - private readonly bool precisionDefined; + private readonly int? _length; + private readonly byte? _precision; + private readonly byte? _scale; public SqlType(DbType dbType) { - this.dbType = dbType; + DbType = dbType; } public SqlType(DbType dbType, int length) { - this.dbType = dbType; - this.length = length; - lengthDefined = true; + DbType = dbType; + _length = length; } public SqlType(DbType dbType, byte precision, byte scale) { - this.dbType = dbType; - this.precision = precision; - this.scale = scale; - precisionDefined = true; + DbType = dbType; + _precision = precision; + _scale = scale; } public SqlType(DbType dbType, byte scale) { - this.dbType = dbType; - this.scale = scale; - ScaleDefined = true; + DbType = dbType; + _scale = scale; } - public DbType DbType - { - get { return dbType; } - } - - public int Length - { - get { return length; } - } - - public byte Precision - { - get { return precision; } - } + public DbType DbType { get; } - public byte Scale - { - get { return scale; } - } + public int Length => _length.GetValueOrDefault(); + public byte Precision => _precision.GetValueOrDefault(); + public byte Scale => _scale.GetValueOrDefault(); + public bool LengthDefined => _length.HasValue; - public bool LengthDefined - { - get { return lengthDefined; } - } + public bool PrecisionDefined => _precision.HasValue; - public bool PrecisionDefined - { - get { return precisionDefined; } - } - public bool ScaleDefined { get; } + public bool ScaleDefined => _scale.HasValue; #region System.Object Members diff --git a/src/NHibernate/StaleObjectStateException.cs b/src/NHibernate/StaleObjectStateException.cs index b53e0155f53..a7e1d8f10cf 100644 --- a/src/NHibernate/StaleObjectStateException.cs +++ b/src/NHibernate/StaleObjectStateException.cs @@ -80,12 +80,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected StaleObjectStateException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; identifier = info.GetValue("identifier", typeof(object)); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -97,6 +100,8 @@ protected StaleObjectStateException(SerializationInfo info, StreamingContext con /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -104,6 +109,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName, typeof(string)); info.AddValue("identifier", identifier, typeof(object)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/StaleStateException.cs b/src/NHibernate/StaleStateException.cs index 2a08cc4e9be..b64ba058b6f 100644 --- a/src/NHibernate/StaleStateException.cs +++ b/src/NHibernate/StaleStateException.cs @@ -13,8 +13,9 @@ public StaleStateException(string message, Exception innerException) : base(mess { } - protected StaleStateException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected StaleStateException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs b/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs index 7f74bc7218c..2c6973137c2 100644 --- a/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs +++ b/src/NHibernate/Transaction/AdoNetWithSystemTransactionFactory.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using System.Threading; using System.Transactions; @@ -23,6 +24,10 @@ public partial class AdoNetWithSystemTransactionFactory : AdoNetTransactionFacto /// protected int SystemTransactionCompletionLockTimeout { get; private set; } /// + /// See . + /// + protected bool IgnoreSessionSynchronizationFailuresOnSystemTransaction { get; private set; } + /// /// See . /// protected bool UseConnectionOnSystemTransactionPrepare { get; private set; } @@ -32,10 +37,12 @@ public override void Configure(IDictionary props) { base.Configure(props); SystemTransactionCompletionLockTimeout = - PropertiesHelper.GetInt32(Cfg.Environment.SystemTransactionCompletionLockTimeout, props, 5000); + PropertiesHelper.GetInt32(Cfg.Environment.SystemTransactionCompletionLockTimeout, props, 1000); if (SystemTransactionCompletionLockTimeout < -1) throw new HibernateException( $"Invalid {Cfg.Environment.SystemTransactionCompletionLockTimeout} value: {SystemTransactionCompletionLockTimeout}. It can not be less than -1."); + IgnoreSessionSynchronizationFailuresOnSystemTransaction = + PropertiesHelper.GetBoolean(Cfg.Environment.IgnoreSessionSynchronizationFailuresOnSystemTransaction, props, false); UseConnectionOnSystemTransactionPrepare = PropertiesHelper.GetBoolean(Cfg.Environment.UseConnectionOnSystemTransactionPrepare, props, true); } @@ -129,7 +136,7 @@ protected virtual ITransactionContext CreateAndEnlistMainContext( { var transactionContext = new SystemTransactionContext( session, transaction, SystemTransactionCompletionLockTimeout, - UseConnectionOnSystemTransactionPrepare); + UseConnectionOnSystemTransactionPrepare, IgnoreSessionSynchronizationFailuresOnSystemTransaction); transactionContext.EnlistedTransaction.EnlistVolatile( transactionContext, UseConnectionOnSystemTransactionPrepare @@ -188,6 +195,7 @@ public class SystemTransactionContext : ITransactionContext, IEnlistmentNotifica private readonly ISessionImplementor _session; private readonly bool _useConnectionOnSystemTransactionPrepare; + private readonly bool _ignoreSessionSynchronizationFailures; private readonly System.Transactions.Transaction _originalTransaction; private readonly ManualResetEventSlim _lock = new ManualResetEventSlim(true); private volatile bool _needCompletionLocking = true; @@ -203,6 +211,8 @@ public class SystemTransactionContext : ITransactionContext, IEnlistmentNotifica /// The transaction into which the context will be enlisted. /// See . /// See . + // Since 5.6 + [Obsolete("Use overload with an additionnal boolean parameter")] public SystemTransactionContext( ISessionImplementor session, System.Transactions.Transaction transaction, @@ -216,6 +226,29 @@ public SystemTransactionContext( _useConnectionOnSystemTransactionPrepare = useConnectionOnSystemTransactionPrepare; } + /// + /// Default constructor. + /// + /// The session to enlist with the transaction. + /// The transaction into which the context will be enlisted. + /// See . + /// See . + /// See . + public SystemTransactionContext( + ISessionImplementor session, + System.Transactions.Transaction transaction, + int systemTransactionCompletionLockTimeout, + bool useConnectionOnSystemTransactionPrepare, + bool ignoreSessionSynchronizationFailures) + { + _session = session ?? throw new ArgumentNullException(nameof(session)); + _originalTransaction = transaction ?? throw new ArgumentNullException(nameof(transaction)); + EnlistedTransaction = transaction.Clone(); + _systemTransactionCompletionLockTimeout = systemTransactionCompletionLockTimeout; + _useConnectionOnSystemTransactionPrepare = useConnectionOnSystemTransactionPrepare; + _ignoreSessionSynchronizationFailures = ignoreSessionSynchronizationFailures; + } + /// public virtual void Wait() { @@ -242,9 +275,9 @@ public virtual void Wait() // Remove the block then throw. Unlock(); throw new HibernateException( - $"Synchronization timeout for transaction completion. Either raise" + - $"{Cfg.Environment.SystemTransactionCompletionLockTimeout}, or check all scopes are properly" + - $"disposed and/or all direct System.Transaction.Current changes are properly managed."); + "A synchronization timeout occurred at transaction completion. Either raise " + + $"{Cfg.Environment.SystemTransactionCompletionLockTimeout}, or check all scopes are properly " + + "disposed and/or all direct System.Transaction.Current changes are properly managed."); } catch (HibernateException) { @@ -266,8 +299,8 @@ protected virtual void Lock() { if (!_needCompletionLocking || _isDisposed) return; - _needCompletionLocking = false; _lock.Reset(); + _needCompletionLocking = false; } /// @@ -418,23 +451,20 @@ void IEnlistmentNotification.InDoubt(Enlistment enlistment) /// callback, if this is an in-doubt callback. protected virtual void ProcessSecondPhase(Enlistment enlistment, bool? success) { - using (_session.BeginContext()) - { - _logger.Debug( - success.HasValue - ? success.Value - ? "Committing system transaction" - : "Rolled back system transaction" - : "System transaction is in doubt"); + _logger.Debug( + success.HasValue + ? success.Value + ? "Committing system transaction" + : "Rolled back system transaction" + : "System transaction is in doubt"); - try - { - CompleteTransaction(success ?? false); - } - finally - { - enlistment.Done(); - } + try + { + CompleteTransaction(success ?? false); + } + finally + { + enlistment.Done(); } } @@ -454,10 +484,47 @@ protected virtual void CompleteTransaction(bool isCommitted) // do an early exit here in such case. if (!IsInActiveTransaction) return; + Lock(); + // In case of a rollback due to a timeout, we may have the session disposal running concurrently + // to the transaction completion in a way our current locking mechanism cannot fully protect: the + // session disposal "BeginProcess" can go through the Wait before it is locked but flag the + // session as processing after the transaction completion has read it as not processing. To dodge + // that very unlikely case, we could consider the session as still processing initially regardless + // of its actual status in case of rollback by changing below condition to + // "!isCommitted || _session.IsProcessing()". That would cause a Thread.Sleep in all rollback cases. + // That would reinforce the impracticality of that concurrency possibility, but with an ugly crutch. + var isSessionProcessing = _session.IsProcessing(); try { // Allow transaction completed actions to run while others stay blocked. _bypassLock.Value = true; + // Ensure no other session processing is still ongoing. In case of a transaction timeout, the transaction is + // cancelled on a new thread even for non-distributed scopes. So, the session could be doing some processing, + // and will not be interrupted until attempting some usage of the connection. See #3355. + // Thread safety of a concurrent session BeginProcess is ensured by the Wait performed by BeginProcess. + if (isSessionProcessing) + { + var timeOutGuard = new Stopwatch(); + timeOutGuard.Start(); + while (isSessionProcessing && timeOutGuard.ElapsedMilliseconds < _systemTransactionCompletionLockTimeout) + { + // Naïve yield. + Thread.Sleep(10); + isSessionProcessing = _session.IsProcessing(); + } + if (isSessionProcessing) + { + // Throwing would give up attempting to close the session if need be, which may still succeed. So, + // just log an error. + _logger.Warn( + "A synchronization timeout occurred at transaction completion: the session is still processing. " + + "Attempting to finalize the transaction concurrently, which may cause a thread concurrency failure. " + + "You may raise {0} if it is set too low. It may also be a limitation of the data provider, " + + "like locks applied on its side while processing transaction cancellations occurring on concurrent threads, " + + "thus preventing the session to finish its current processing during a transaction cancellation.", + Cfg.Environment.SystemTransactionCompletionLockTimeout); + } + } using (_session.BeginContext()) { // Flag active as false before running actions, otherwise the session may not cleanup as much @@ -477,7 +544,7 @@ protected virtual void CompleteTransaction(bool isCommitted) // within scopes, although mixing is not advised. if (!ShouldCloseSessionOnSystemTransactionCompleted) _session.ConnectionManager.EnlistIfRequired(null); - + _session.AfterTransactionCompletion(isCommitted, null); foreach (var dependentSession in _session.ConnectionManager.DependentSessions) dependentSession.AfterTransactionCompletion(isCommitted, null); @@ -497,6 +564,18 @@ protected virtual void CompleteTransaction(bool isCommitted) // Dispose releases blocked threads by the way. Dispose(); } + + if (isSessionProcessing && !_ignoreSessionSynchronizationFailures) + { + throw new HibernateException( + "A synchronization timeout occurred at transaction completion: the session was still processing. " + + $"You may raise {Cfg.Environment.SystemTransactionCompletionLockTimeout} if it is set too low. " + + "It may also be a limitation of the data provider, " + + "like locks applied on its side while processing transaction cancellations occurring on concurrent threads, " + + "thus preventing the session to finish its current processing during a transaction cancellation. " + + $"In such case, you may enable {Cfg.Environment.IgnoreSessionSynchronizationFailuresOnSystemTransaction}, " + + $"and possibly lower {Cfg.Environment.SystemTransactionCompletionLockTimeout}."); + } } private static void Cleanup(ISessionImplementor session) @@ -504,7 +583,7 @@ private static void Cleanup(ISessionImplementor session) foreach (var dependentSession in session.ConnectionManager.DependentSessions.ToList()) { var dependentContext = dependentSession.TransactionContext; - // Do not nullify TransactionContext here, could create a race condition with + // Do not nullify TransactionContext here, it could create a race condition with // would be await-er on session for disposal (test cases cleanup checks by example). if (dependentContext == null) continue; diff --git a/src/NHibernate/TransactionException.cs b/src/NHibernate/TransactionException.cs index e5964844593..f9a91236492 100644 --- a/src/NHibernate/TransactionException.cs +++ b/src/NHibernate/TransactionException.cs @@ -41,8 +41,10 @@ public TransactionException(string message, Exception innerException) : base(mes /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TransactionException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/TransientObjectException.cs b/src/NHibernate/TransientObjectException.cs index eb55554248e..42e1eb10da3 100644 --- a/src/NHibernate/TransientObjectException.cs +++ b/src/NHibernate/TransientObjectException.cs @@ -29,8 +29,10 @@ public TransientObjectException(string message) : base(message) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TransientObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs b/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs index 88fd793bc35..d4ae15b5aa4 100644 --- a/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs +++ b/src/NHibernate/Tuple/Component/PocoComponentTuplizer.cs @@ -3,6 +3,7 @@ using NHibernate.Bytecode.Lightweight; using NHibernate.Intercept; using NHibernate.Properties; +using NHibernate.Util; namespace NHibernate.Tuple.Component { @@ -155,12 +156,12 @@ protected internal override IInstantiator BuildInstantiator(Mapping.Component co protected internal override IGetter BuildGetter(Mapping.Component component, Mapping.Property prop) { - return prop.GetGetter(component.ComponentClass); + return prop.GetGetter(component.ComponentClass.UnwrapIfNullable()); } protected internal override ISetter BuildSetter(Mapping.Component component, Mapping.Property prop) { - return prop.GetSetter(component.ComponentClass); + return prop.GetSetter(component.ComponentClass.UnwrapIfNullable()); } protected void SetReflectionOptimizer() diff --git a/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs b/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs index 07abc64fce3..c926bd60d9e 100644 --- a/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs +++ b/src/NHibernate/Tuple/Entity/DynamicMapEntityTuplizer.cs @@ -13,7 +13,7 @@ public class DynamicMapEntityTuplizer : AbstractEntityTuplizer { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(PocoEntityTuplizer)); - internal DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) + public DynamicMapEntityTuplizer(EntityMetamodel entityMetamodel, PersistentClass mappingInfo) : base(entityMetamodel, mappingInfo) { // NH different behavior fo NH-1587 diff --git a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs index 2a02711b2bf..c5dc3478f67 100644 --- a/src/NHibernate/Tuple/Entity/EntityMetamodel.cs +++ b/src/NHibernate/Tuple/Entity/EntityMetamodel.cs @@ -449,7 +449,7 @@ private void MapIdentifierPropertyTypes(string path, IType propertyType) for (var i = 0; i < componentType.PropertyNames.Length; i++) { MapIdentifierPropertyTypes( - !string.IsNullOrEmpty(path) ? $"{path}.{componentType.PropertyNames[i]}" : componentType.PropertyNames[i], + !string.IsNullOrEmpty(path) ? string.Intern($"{path}.{componentType.PropertyNames[i]}") : componentType.PropertyNames[i], componentType.Subtypes[i]); } } diff --git a/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs b/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs index 0a4075ca643..7584c3456db 100644 --- a/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs +++ b/src/NHibernate/Tuple/Entity/PocoEntityInstantiator.cs @@ -37,7 +37,7 @@ protected override object CreateInstance() return base.CreateInstance(); } - var entity = _proxyFactory.GetFieldInterceptionProxy(base.CreateInstance); + var entity = ProxyFactoryExtensions.GetFieldInterceptionProxy(_proxyFactory, base.CreateInstance); _entityMetamodel.BytecodeEnhancementMetadata.InjectInterceptor(entity, null); return entity; } diff --git a/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs b/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs index 3913d678032..2a79d56ca74 100644 --- a/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs +++ b/src/NHibernate/Tuple/Entity/PocoEntityTuplizer.cs @@ -12,6 +12,7 @@ using NHibernate.Util; using System.Runtime.Serialization; using NHibernate.Bytecode.Lightweight; +using NHibernate.Intercept; namespace NHibernate.Tuple.Entity { @@ -306,6 +307,16 @@ public override bool IsLifecycleImplementor public override void SetPropertyValue(object entity, int i, object value) { + // If there is no property setter we need to manually intercept value for proper lazy property handling. + if (IsInstrumented && setters[i].PropertyName == null) + { + IFieldInterceptor interceptor = _enhancementMetadata.ExtractInterceptor(entity); + if (interceptor != null) + { + value = interceptor.Intercept(entity, EntityMetamodel.PropertyNames[i], value, true); + } + } + if (isBytecodeProviderImpl && optimizer?.AccessOptimizer != null) { optimizer.AccessOptimizer.SetPropertyValue(entity, i, value); diff --git a/src/NHibernate/Tuple/PocoInstantiator.cs b/src/NHibernate/Tuple/PocoInstantiator.cs index 6af0682e6c6..3f4258e921d 100644 --- a/src/NHibernate/Tuple/PocoInstantiator.cs +++ b/src/NHibernate/Tuple/PocoInstantiator.cs @@ -100,11 +100,13 @@ public object Instantiate() { throw new InstantiationException("Cannot instantiate abstract class or interface: ", mappedClass); } + // 6.0 TODO: Remove if statement if (generateFieldInterceptionProxy) { - return proxyFactory.GetFieldInterceptionProxy(CreateInstance); + return ProxyFactoryExtensions.GetFieldInterceptionProxy(proxyFactory, CreateInstance); } + return CreateInstance(); } diff --git a/src/NHibernate/Type/AbstractBinaryType.cs b/src/NHibernate/Type/AbstractBinaryType.cs index 2e5882731e6..a6adc443fdc 100644 --- a/src/NHibernate/Type/AbstractBinaryType.cs +++ b/src/NHibernate/Type/AbstractBinaryType.cs @@ -90,11 +90,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return ToExternalFormat(buffer); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override int GetHashCode(object x) { byte[] bytes = ToInternalFormat(x); diff --git a/src/NHibernate/Type/AbstractCharType.cs b/src/NHibernate/Type/AbstractCharType.cs index 5efb630c16c..dd53c1de5f2 100644 --- a/src/NHibernate/Type/AbstractCharType.cs +++ b/src/NHibernate/Type/AbstractCharType.cs @@ -11,14 +11,13 @@ namespace NHibernate.Type [Serializable] public abstract class AbstractCharType : PrimitiveType, IDiscriminatorType { - public AbstractCharType(SqlType sqlType) - : base(sqlType) {} - - public override object DefaultValue + /// + public AbstractCharType(SqlType sqlType) : base(sqlType) { - get { throw new NotSupportedException("not a valid id type"); } } + public override object DefaultValue => throw new NotSupportedException("not a valid id type"); + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { string dbValue = Convert.ToString(rs[index]); @@ -30,20 +29,9 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return '\0'; // This line should never be executed } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } + public override System.Type PrimitiveClass => typeof(char); - public override System.Type PrimitiveClass - { - get { return typeof(char); } - } - - public override System.Type ReturnedClass - { - get { return typeof(char); } - } + public override System.Type ReturnedClass => typeof(char); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { @@ -51,9 +39,7 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return '\'' + value.ToString() + '\''; - } + => dialect.ToStringLiteral(value.ToString(), SqlType); // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml // attribute value is irrelevant to the method behavior. diff --git a/src/NHibernate/Type/AbstractDateTimeType.cs b/src/NHibernate/Type/AbstractDateTimeType.cs index 8f95323cb78..fb197523518 100644 --- a/src/NHibernate/Type/AbstractDateTimeType.cs +++ b/src/NHibernate/Type/AbstractDateTimeType.cs @@ -14,7 +14,7 @@ namespace NHibernate.Type [Serializable] public abstract partial class AbstractDateTimeType : PrimitiveType, IIdentifierType, ILiteralType, IVersionType { - private static readonly DateTime BaseDateValue = DateTime.MinValue; + private static readonly object BaseDateValue = DateTime.MinValue; /// /// Returns the for the type. @@ -31,17 +31,12 @@ public abstract partial class AbstractDateTimeType : PrimitiveType, IIdentifierT /// otherwise. protected virtual DateTime Now => Kind == DateTimeKind.Utc ? DateTime.UtcNow : DateTime.Now; - /// - /// Default constructor. - /// - protected AbstractDateTimeType() : base(SqlTypeFactory.DateTime) + /// + protected AbstractDateTimeType() : this(SqlTypeFactory.DateTime) { } - /// - /// Constructor for overriding the default . - /// - /// The to use. + /// protected AbstractDateTimeType(SqlType sqlTypeDateTime) : base(sqlTypeDateTime) { } @@ -58,10 +53,6 @@ protected virtual DateTime AdjustDateTime(DateTime dateValue) => public override object Get(DbDataReader rs, int index, ISessionImplementor session) => GetDateTime(rs, index, session); - /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) => - Get(rs, rs.GetOrdinal(name), session); - /// /// Get the in the for the Property. /// @@ -176,7 +167,7 @@ public override object FromStringValue(string xml) public override object DefaultValue => BaseDateValue; /// - public override string ObjectToSQLString(object value, Dialect.Dialect dialect) => - "'" + (DateTime) value + "'"; + public override string ObjectToSQLString(object value, Dialect.Dialect dialect) + => dialect.ToStringLiteral(((DateTime) value).ToString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/AbstractStringType.cs b/src/NHibernate/Type/AbstractStringType.cs index 9d47aaf07ff..eb820a1c234 100644 --- a/src/NHibernate/Type/AbstractStringType.cs +++ b/src/NHibernate/Type/AbstractStringType.cs @@ -76,11 +76,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return Convert.ToString(rs[index]); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Convert.ToString(rs[name]); - } - public override bool IsEqual(object x, object y) { return Comparer.Equals(x, y); @@ -134,10 +129,9 @@ public object StringToObject(string xml) #region ILiteralType Members + /// public string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + (string)value + "'"; - } + => dialect.ToStringLiteral((string)value, SqlType); #endregion diff --git a/src/NHibernate/Type/BooleanType.cs b/src/NHibernate/Type/BooleanType.cs index 2a154211b7b..d93e23e0385 100644 --- a/src/NHibernate/Type/BooleanType.cs +++ b/src/NHibernate/Type/BooleanType.cs @@ -43,11 +43,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return GetBooleanAsObject(Convert.ToBoolean(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return GetBooleanAsObject(Convert.ToBoolean(rs[name])); - } - public override System.Type PrimitiveClass => typeof(bool); public override System.Type ReturnedClass => typeof(bool); diff --git a/src/NHibernate/Type/ByteType.cs b/src/NHibernate/Type/ByteType.cs index ed8196bac67..3047665a943 100644 --- a/src/NHibernate/Type/ByteType.cs +++ b/src/NHibernate/Type/ByteType.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -15,10 +16,10 @@ namespace NHibernate.Type [Serializable] public partial class ByteType : PrimitiveType, IDiscriminatorType, IVersionType { - private static readonly byte ZERO = 0; + private static readonly object ZeroObject = (byte) 0; - public ByteType() - : base(SqlTypeFactory.Byte) + /// + public ByteType() : base(SqlTypeFactory.Byte) { } @@ -32,24 +33,9 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi }; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return rs[name] switch - { - BigInteger bi => (byte) bi, - var c => Convert.ToByte(c) - }; - } + public override System.Type ReturnedClass => typeof(byte); - public override System.Type ReturnedClass - { - get { return typeof(byte); } - } - - public override System.Type PrimitiveClass - { - get { return typeof(byte); } - } + public override System.Type PrimitiveClass => typeof(byte); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { @@ -57,14 +43,11 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme dp.Value = dp.DbType == DbType.Int16 ? Convert.ToInt16(value) : Convert.ToByte(value); } - public override string Name - { - get { return "Byte"; } - } + public override string Name => "Byte"; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((byte)value).ToString(CultureInfo.InvariantCulture); } // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml @@ -93,17 +76,11 @@ public virtual object Next(object current, ISessionImplementor session) public virtual object Seed(ISessionImplementor session) { - return ZERO; + return ZeroObject; } - public IComparer Comparator - { - get { return Comparer.DefaultInvariant; } - } + public IComparer Comparator => Comparer.DefaultInvariant; - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; } } diff --git a/src/NHibernate/Type/CharBooleanType.cs b/src/NHibernate/Type/CharBooleanType.cs index 53dc6a9abb3..9536ce4c790 100644 --- a/src/NHibernate/Type/CharBooleanType.cs +++ b/src/NHibernate/Type/CharBooleanType.cs @@ -40,11 +40,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override void Set(DbCommand cmd, Object value, int index, ISessionImplementor session) { cmd.Parameters[index].Value = ToCharacter(value); @@ -56,9 +51,7 @@ private string ToCharacter(object value) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ToCharacter(value) + "'"; - } + => dialect.ToStringLiteral(ToCharacter(value), SqlType); // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml // attribute value is irrelevant to the method behavior. diff --git a/src/NHibernate/Type/ComponentType.cs b/src/NHibernate/Type/ComponentType.cs index cf9cdbf552b..3c3ffe9d2d8 100644 --- a/src/NHibernate/Type/ComponentType.cs +++ b/src/NHibernate/Type/ComponentType.cs @@ -156,14 +156,6 @@ public override bool IsDirty(object x, object y, ISessionImplementor session) { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); for (int i = 0; i < xvalues.Length; i++) @@ -182,14 +174,6 @@ public override bool IsDirty(object x, object y, bool[] checkable, ISessionImple { return false; } - /* - * NH Different behavior : we don't use the shortcut because NH-1101 - * let the tuplizer choose how cosiderer properties when the component is null. - */ - if (EntityMode != EntityMode.Poco && (x == null || y == null)) - { - return true; - } object[] xvalues = GetPropertyValues(x); object[] yvalues = GetPropertyValues(y); int loc = 0; diff --git a/src/NHibernate/Type/CultureInfoType.cs b/src/NHibernate/Type/CultureInfoType.cs index 47daf666588..4ae13cf364e 100644 --- a/src/NHibernate/Type/CultureInfoType.cs +++ b/src/NHibernate/Type/CultureInfoType.cs @@ -8,12 +8,12 @@ namespace NHibernate.Type { /// - /// Maps a Property + /// Maps a Property /// to a column. /// /// /// CultureInfoType stores the culture name (not the Culture ID) of the - /// in the DB. + /// in the DB. /// [Serializable] public partial class CultureInfoType : ImmutableType, ILiteralType @@ -22,16 +22,14 @@ internal CultureInfoType() : base(new StringSqlType(5)) { } - /// - public override object Get(DbDataReader rs, int index, ISessionImplementor session) + internal CultureInfoType(StringSqlType sqlType) : base(sqlType) { - return ParseStringRepresentation(NHibernateUtil.String.Get(rs, index, session)); } /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return Get(rs, rs.GetOrdinal(name), session); + return ParseStringRepresentation(NHibernateUtil.String.Get(rs, index, session)); } /// diff --git a/src/NHibernate/Type/DateTimeOffSetType.cs b/src/NHibernate/Type/DateTimeOffSetType.cs index 37837aec289..78d4f9b233c 100644 --- a/src/NHibernate/Type/DateTimeOffSetType.cs +++ b/src/NHibernate/Type/DateTimeOffSetType.cs @@ -14,47 +14,26 @@ namespace NHibernate.Type [Serializable] public partial class DateTimeOffsetType : PrimitiveType, IIdentifierType, ILiteralType, IVersionType { - static readonly DateTimeOffset BaseDateValue = DateTimeOffset.MinValue; + private static readonly object BaseDateValue = DateTimeOffset.MinValue; - /// - /// Default constructor. - /// public DateTimeOffsetType() : base(SqlTypeFactory.DateTimeOffSet) { } - /// - /// Constructor for specifying a datetimeoffset with a scale. Use . - /// - /// The sql type to use for the type. + /// public DateTimeOffsetType(DateTimeOffsetSqlType sqlType) : base(sqlType) { } - public override string Name - { - get { return "DateTimeOffset"; } - } + public override string Name => "DateTimeOffset"; - public override System.Type ReturnedClass - { - get { return typeof (DateTimeOffset); } - } + public override System.Type ReturnedClass => typeof (DateTimeOffset); - public override System.Type PrimitiveClass - { - get { return typeof (DateTimeOffset); } - } + public override System.Type PrimitiveClass => typeof (DateTimeOffset); - public override object DefaultValue - { - get { return BaseDateValue; } - } + public override object DefaultValue => BaseDateValue; - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { @@ -73,11 +52,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public object Next(object current, ISessionImplementor session) { return Seed(session); @@ -155,8 +129,6 @@ public override object FromStringValue(string xml) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((DateTimeOffset) value) + "'"; - } + => dialect.ToStringLiteral(((DateTimeOffset) value).ToString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/DateType.cs b/src/NHibernate/Type/DateType.cs index 76d3fbb99e9..65b7024b646 100644 --- a/src/NHibernate/Type/DateType.cs +++ b/src/NHibernate/Type/DateType.cs @@ -21,11 +21,12 @@ public class DateType : AbstractDateTimeType, IParameterizedType // Since v5.0 [Obsolete("Use DateTime.MinValue.")] public static readonly DateTime BaseDateValue = DateTime.MinValue; - private DateTime customBaseDate = _baseDateValue; private static readonly DateTime _baseDateValue = DateTime.MinValue; - /// Default constructor + private object customBaseDate = _baseDateValue; + + /// public DateType() : base(SqlTypeFactory.Date) { } @@ -93,8 +94,8 @@ public override string ToString(object val) => public override object DefaultValue => customBaseDate; /// - public override string ObjectToSQLString(object value, Dialect.Dialect dialect) => - "\'" + ((DateTime)value).ToShortDateString() + "\'"; + public override string ObjectToSQLString(object value, Dialect.Dialect dialect) + => dialect.ToStringLiteral(((DateTime) value).ToShortDateString(), SqlTypeFactory.GetAnsiString(50)); // Since v5 [Obsolete("Its only parameter, BaseValue, is obsolete.")] diff --git a/src/NHibernate/Type/DecimalType.cs b/src/NHibernate/Type/DecimalType.cs index 158fa028fc7..1987ae23280 100644 --- a/src/NHibernate/Type/DecimalType.cs +++ b/src/NHibernate/Type/DecimalType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -13,11 +14,15 @@ namespace NHibernate.Type [Serializable] public class DecimalType : PrimitiveType, IIdentifierType { + private static readonly object ZeroObject = 0m; + + /// public DecimalType() : this(SqlTypeFactory.Decimal) { } + /// public DecimalType(SqlType sqlType) : base(sqlType) { } @@ -27,35 +32,18 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return Convert.ToDecimal(rs[index]); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Convert.ToDecimal(rs[name]); - } - - public override System.Type ReturnedClass - { - get { return typeof(Decimal); } - } + public override System.Type ReturnedClass => typeof(Decimal); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { st.Parameters[index].Value = Convert.ToDecimal(value); } - public override string Name - { - get { return "Decimal"; } - } + public override string Name => "Decimal"; - public override System.Type PrimitiveClass - { - get { return typeof (Decimal); } - } + public override System.Type PrimitiveClass => typeof (Decimal); - public override object DefaultValue - { - get { return 0m; } - } + public override object DefaultValue => ZeroObject; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] @@ -66,7 +54,7 @@ public override object FromStringValue(string xml) public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((decimal)value).ToString(CultureInfo.InvariantCulture); } // 6.0 TODO: rename "xml" parameter as "value": it is not a xml string. The fact it generally comes from a xml diff --git a/src/NHibernate/Type/DoubleType.cs b/src/NHibernate/Type/DoubleType.cs index 9fbe8a0ed71..880842b5ba8 100644 --- a/src/NHibernate/Type/DoubleType.cs +++ b/src/NHibernate/Type/DoubleType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -14,25 +15,21 @@ namespace NHibernate.Type [Serializable] public class DoubleType : PrimitiveType { - /// + private static readonly object ZeroObject = 0D; + + /// public DoubleType() : base(SqlTypeFactory.Double) { } - public DoubleType(SqlType sqlType) : base(sqlType) {} - - public override object Get(DbDataReader rs, int index, ISessionImplementor session) + /// + public DoubleType(SqlType sqlType) : base(sqlType) { - return rs[index] switch - { - BigInteger bi => (double) bi, - var v => Convert.ToDouble(v) - }; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { - return rs[name] switch + return rs[index] switch { BigInteger bi => (double) bi, var v => Convert.ToDouble(v) @@ -40,10 +37,7 @@ public override object Get(DbDataReader rs, string name, ISessionImplementor ses } /// - public override System.Type ReturnedClass - { - get { return typeof(double); } - } + public override System.Type ReturnedClass => typeof(double); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { @@ -51,10 +45,7 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen } /// - public override string Name - { - get { return "Double"; } - } + public override string Name => "Double"; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] @@ -63,19 +54,13 @@ public override object FromStringValue(string xml) return double.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(double); } - } + public override System.Type PrimitiveClass => typeof(double); - public override object DefaultValue - { - get { return 0D; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((double)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/EnumCharType.cs b/src/NHibernate/Type/EnumCharType.cs index ece3684ff6f..8ebf6b47020 100644 --- a/src/NHibernate/Type/EnumCharType.cs +++ b/src/NHibernate/Type/EnumCharType.cs @@ -119,11 +119,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return "enumchar - " + this.ReturnedClass.Name; } @@ -171,8 +166,6 @@ public override object FromStringValue(string xml) } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return '\'' + GetValue(value).ToString() + '\''; - } + => dialect.ToStringLiteral(GetValue(value).ToString(), SqlType); } } diff --git a/src/NHibernate/Type/EnumStringType.cs b/src/NHibernate/Type/EnumStringType.cs index 168ce03291f..01f8ce0d6c0 100644 --- a/src/NHibernate/Type/EnumStringType.cs +++ b/src/NHibernate/Type/EnumStringType.cs @@ -148,11 +148,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/GuidType.cs b/src/NHibernate/Type/GuidType.cs index a883f3a6b5a..1c26e399418 100644 --- a/src/NHibernate/Type/GuidType.cs +++ b/src/NHibernate/Type/GuidType.cs @@ -13,7 +13,9 @@ namespace NHibernate.Type [Serializable] public class GuidType : PrimitiveType, IDiscriminatorType { - /// + private static readonly object EmptyObject = Guid.Empty; + + /// public GuidType() : base(SqlTypeFactory.Guid) { } @@ -33,16 +35,8 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return new Guid(Convert.ToString(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// - public override System.Type ReturnedClass - { - get { return typeof(Guid); } - } + public override System.Type ReturnedClass => typeof(Guid); public override void Set(DbCommand cmd, object value, int index, ISessionImplementor session) { @@ -52,10 +46,7 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme } /// - public override string Name - { - get { return "Guid"; } - } + public override string Name => "Guid"; // Since 5.2 [Obsolete("This method has no more usages and will be removed in a future version.")] @@ -76,19 +67,13 @@ public object StringToObject(string xml) #pragma warning restore 618 } - public override System.Type PrimitiveClass - { - get { return typeof(Guid); } - } + public override System.Type PrimitiveClass => typeof(Guid); - public override object DefaultValue - { - get { return Guid.Empty; } - } + public override object DefaultValue => EmptyObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return "'" + value + "'"; + return dialect.ToStringLiteral(value.ToString(), SqlTypeFactory.GetAnsiString(50)); } } } diff --git a/src/NHibernate/Type/Int16Type.cs b/src/NHibernate/Type/Int16Type.cs index f55c1d1b2f5..8e1566ae42b 100644 --- a/src/NHibernate/Type/Int16Type.cs +++ b/src/NHibernate/Type/Int16Type.cs @@ -1,11 +1,12 @@ using System; using System.Collections; -using System.Data.Common; -using NHibernate.Engine; -using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using System.Data.Common; +using System.Globalization; using System.Numerics; +using NHibernate.Engine; +using NHibernate.SqlTypes; namespace NHibernate.Type { @@ -16,18 +17,16 @@ namespace NHibernate.Type [Serializable] public partial class Int16Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = (short) 0; + + /// public Int16Type() : base(SqlTypeFactory.Int16) { } /// - public override string Name - { - get { return "Int16"; } - } + public override string Name => "Int16"; - private static readonly Int16 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,26 +43,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name]switch - { - BigInteger bi => (short) bi, - var c => Convert.ToInt16(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(Int16); } - } + public override System.Type ReturnedClass => typeof(Int16); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -92,8 +72,6 @@ public override object FromStringValue(string xml) return Int16.Parse(xml); } - #region IVersionType Members - public virtual object Next(object current, ISessionImplementor session) { return (Int16)((Int16)current + 1); @@ -104,26 +82,15 @@ public virtual object Seed(ISessionImplementor session) return (Int16)1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } - - #endregion + public IComparer Comparator => Comparer.Default; - public override System.Type PrimitiveClass - { - get { return typeof (Int16); } - } + public override System.Type PrimitiveClass => typeof (Int16); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((short)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/Int32Type.cs b/src/NHibernate/Type/Int32Type.cs index 02371f1bc3c..914b512c97e 100644 --- a/src/NHibernate/Type/Int32Type.cs +++ b/src/NHibernate/Type/Int32Type.cs @@ -1,11 +1,12 @@ using System; using System.Collections; -using System.Data.Common; -using NHibernate.Engine; -using NHibernate.SqlTypes; using System.Collections.Generic; using System.Data; +using System.Data.Common; +using System.Globalization; using System.Numerics; +using NHibernate.Engine; +using NHibernate.SqlTypes; namespace NHibernate.Type { @@ -16,25 +17,24 @@ namespace NHibernate.Type [Serializable] public partial class Int32Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0; + + /// public Int32Type() : base(SqlTypeFactory.Int32) { } /// - public override string Name - { - get { return "Int32"; } - } - - private static readonly Int32 ZERO = 0; + public override string Name => "Int32"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try { - return rs[index] switch + var value = rs[index]; + return value switch { + int _ => value, BigInteger bi => (int) bi, var c => Convert.ToInt32(c) }; @@ -45,26 +45,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (int) bi, - var c => Convert.ToInt32(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(Int32); } - } + public override System.Type ReturnedClass => typeof(Int32); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -105,26 +86,17 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(Int32); } - } + public override System.Type PrimitiveClass => typeof(Int32); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((int)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/Int64Type.cs b/src/NHibernate/Type/Int64Type.cs index 3fa7892f4bf..0a93fad7138 100644 --- a/src/NHibernate/Type/Int64Type.cs +++ b/src/NHibernate/Type/Int64Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -16,18 +17,16 @@ namespace NHibernate.Type [Serializable] public partial class Int64Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0L; + + /// public Int64Type() : base(SqlTypeFactory.Int64) { } /// - public override string Name - { - get { return "Int64"; } - } + public override string Name => "Int64"; - private static readonly Int64 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,26 +43,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (long) bi, - var c => Convert.ToInt64(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(Int64); } - } + public override System.Type ReturnedClass => typeof(Int64); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -104,26 +84,17 @@ public virtual object Seed(ISessionImplementor session) return 1L; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(Int64); } - } + public override System.Type PrimitiveClass => typeof(Int64); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((long)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/NullableType.cs b/src/NHibernate/Type/NullableType.cs index 883894ee971..caf386a631f 100644 --- a/src/NHibernate/Type/NullableType.cs +++ b/src/NHibernate/Type/NullableType.cs @@ -80,7 +80,10 @@ protected NullableType(SqlType sqlType) /// Most implementors just call the /// overload of this method. /// - public abstract object Get(DbDataReader rs, string name, ISessionImplementor session); + // Since v5.6 + [Obsolete("This method has no more usages and will be removed in a future version.")] + public virtual object Get(DbDataReader rs, string name, ISessionImplementor session) => + Get(rs, rs.GetOrdinal(name), session); /// /// A representation of the value to be embedded in an XML element diff --git a/src/NHibernate/Type/PersistentEnumType.cs b/src/NHibernate/Type/PersistentEnumType.cs index 51c10a4313f..d384a471abe 100644 --- a/src/NHibernate/Type/PersistentEnumType.cs +++ b/src/NHibernate/Type/PersistentEnumType.cs @@ -226,11 +226,6 @@ public override void Set(DbCommand cmd, object value, int index, ISessionImpleme cmd.Parameters[index].Value = value != null ? GetValue(value) : DBNull.Value; } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override string Name { get { return ReturnedClass.FullName; } @@ -299,7 +294,7 @@ public class EnumType : PersistentEnumType public EnumType() : base(typeof (T)) { System.Type type = GetType(); - typeName = type.FullName + ", " + type.Assembly.GetName().Name; + typeName = string.Intern(type.FullName + ", " + type.Assembly.GetName().Name); } public override string Name diff --git a/src/NHibernate/Type/PrimitiveType.cs b/src/NHibernate/Type/PrimitiveType.cs index 7b452db3481..2956f394eb5 100644 --- a/src/NHibernate/Type/PrimitiveType.cs +++ b/src/NHibernate/Type/PrimitiveType.cs @@ -10,19 +10,15 @@ namespace NHibernate.Type [Serializable] public abstract class PrimitiveType : ImmutableType, ILiteralType { - /// - /// Initialize a new instance of the PrimitiveType class using a . - /// - /// The underlying . - protected PrimitiveType(SqlType sqlType) - : base(sqlType) {} + /// + protected PrimitiveType(SqlType sqlType) : base(sqlType) + { + } public abstract System.Type PrimitiveClass { get; } public abstract object DefaultValue { get; } - #region ILiteralType Members - /// /// When implemented by a class, return a representation /// of the value, suitable for embedding in an SQL statement @@ -32,8 +28,6 @@ protected PrimitiveType(SqlType sqlType) /// A string that containts a well formed SQL Statement. public abstract string ObjectToSQLString(object value, Dialect.Dialect dialect); - #endregion - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/SByteType.cs b/src/NHibernate/Type/SByteType.cs index 2f861bda232..12728690e63 100644 --- a/src/NHibernate/Type/SByteType.cs +++ b/src/NHibernate/Type/SByteType.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -16,18 +17,16 @@ namespace NHibernate.Type [Serializable] public class SByteType : PrimitiveType, IDiscriminatorType { - /// + private static readonly object ZeroObject = (sbyte) 0; + + /// public SByteType() : base(SqlTypeFactory.SByte) { } /// - public override string Name - { - get { return "SByte"; } - } + public override string Name => "SByte"; - private static readonly SByte ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,26 +43,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (sbyte) bi, - var c => Convert.ToSByte(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(SByte); } - } + public override System.Type ReturnedClass => typeof(SByte); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -88,8 +68,6 @@ public override object FromStringValue(string xml) return SByte.Parse(xml); } - #region IVersionType Members - // Since 5.2 [Obsolete("This member has no more usage and will be removed in a future version.")] public virtual object Next(object current, ISessionImplementor session) @@ -106,26 +84,15 @@ public virtual object Seed(ISessionImplementor session) // Since 5.2 [Obsolete("This member has no more usage and will be removed in a future version.")] - public IComparer Comparator - { - get { return Comparer.Default; } - } - - #endregion + public IComparer Comparator => Comparer.Default; - public override System.Type PrimitiveClass - { - get { return typeof(SByte); } - } + public override System.Type PrimitiveClass => typeof(SByte); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((sbyte)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/SerializableType.cs b/src/NHibernate/Type/SerializableType.cs index 54b85ecc3cb..2c38715fbe0 100644 --- a/src/NHibernate/Type/SerializableType.cs +++ b/src/NHibernate/Type/SerializableType.cs @@ -56,11 +56,6 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen binaryType.Set(st, ToBytes(value), index, session); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override object Get(DbDataReader rs, int index, ISessionImplementor session) { byte[] bytes = (byte[]) binaryType.Get(rs, index, session); diff --git a/src/NHibernate/Type/SerializationException.cs b/src/NHibernate/Type/SerializationException.cs index 1118dbf5487..18fe754d3a2 100644 --- a/src/NHibernate/Type/SerializationException.cs +++ b/src/NHibernate/Type/SerializationException.cs @@ -49,8 +49,10 @@ public SerializationException(string message, Exception e) : base(message, e) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected SerializationException(SerializationInfo info, StreamingContext context) : base(info, context) { } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Type/SingleType.cs b/src/NHibernate/Type/SingleType.cs index 0cab527f6a6..aa2b296679a 100644 --- a/src/NHibernate/Type/SingleType.cs +++ b/src/NHibernate/Type/SingleType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -18,20 +19,20 @@ namespace NHibernate.Type [Serializable] public class SingleType : PrimitiveType { - /// - public SingleType() : base(SqlTypeFactory.Single) + private static readonly object ZeroObject = 0F; + + public SingleType() : this(SqlTypeFactory.Single) { } - public SingleType(SqlType sqlType) : base(sqlType) {} - - /// - public override string Name + /// + public SingleType(SqlType sqlType) : base(sqlType) { - get { return "Single"; } } - private static readonly Single ZERO = 0; + /// + public override string Name => "Single"; + public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -48,26 +49,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (float) bi, - var v => Convert.ToSingle(v) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(Single); } - } + public override System.Type ReturnedClass => typeof(Single); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -88,19 +70,13 @@ public override object FromStringValue(string xml) return Single.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(Single); } - } + public override System.Type PrimitiveClass => typeof(Single); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((float)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/TicksType.cs b/src/NHibernate/Type/TicksType.cs index 4fc18a007cd..bc82d101df8 100644 --- a/src/NHibernate/Type/TicksType.cs +++ b/src/NHibernate/Type/TicksType.cs @@ -1,6 +1,7 @@ using System; using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -100,7 +101,7 @@ public override object Seed(ISessionImplementor session) /// public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((DateTime)value).Ticks.ToString() + '\''; + return '\'' + ((DateTime)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeAsTimeSpanType.cs b/src/NHibernate/Type/TimeAsTimeSpanType.cs index e525ecfa555..a91b4f07975 100644 --- a/src/NHibernate/Type/TimeAsTimeSpanType.cs +++ b/src/NHibernate/Type/TimeAsTimeSpanType.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -16,27 +17,20 @@ namespace NHibernate.Type [Serializable] public partial class TimeAsTimeSpanType : PrimitiveType, IVersionType { + private static readonly object ZeroObject = TimeSpan.Zero; private static readonly DateTime BaseDateValue = new DateTime(1753, 01, 01); - /// - /// Default constructor. - /// + /// public TimeAsTimeSpanType() : base(SqlTypeFactory.Time) { } - /// - /// Constructor for specifying a time with a scale. Use . - /// - /// The sql type to use for the type. + /// public TimeAsTimeSpanType(TimeSqlType sqlType) : base(sqlType) { } - public override string Name - { - get { return "TimeAsTimeSpan"; } - } + public override string Name => "TimeAsTimeSpan"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -57,11 +51,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { if (session.Factory.ConnectionProvider.Driver.RequiresTimeSpanForTime) @@ -70,10 +59,7 @@ public override void Set(DbCommand st, object value, int index, ISessionImplemen st.Parameters[index].Value = BaseDateValue.AddTicks(((TimeSpan)value).Ticks); } - public override System.Type ReturnedClass - { - get { return typeof(TimeSpan); } - } + public override System.Type ReturnedClass => typeof(TimeSpan); /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) @@ -111,10 +97,7 @@ public object StringToObject(string xml) return TimeSpan.Parse(xml); } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion @@ -129,19 +112,13 @@ public override object FromStringValue(string xml) return TimeSpan.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(TimeSpan); } - } + public override System.Type PrimitiveClass => typeof(TimeSpan); - public override object DefaultValue - { - get { return TimeSpan.Zero; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((TimeSpan)value).Ticks.ToString() + '\''; + return '\'' + ((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeSpanType.cs b/src/NHibernate/Type/TimeSpanType.cs index 5ca576454b9..b8cf39d8d20 100644 --- a/src/NHibernate/Type/TimeSpanType.cs +++ b/src/NHibernate/Type/TimeSpanType.cs @@ -1,10 +1,11 @@ using System; using System.Collections; +using System.Collections.Generic; +using System.Data; using System.Data.Common; +using System.Globalization; using NHibernate.Engine; using NHibernate.SqlTypes; -using System.Collections.Generic; -using System.Data; namespace NHibernate.Type { @@ -14,17 +15,14 @@ namespace NHibernate.Type [Serializable] public partial class TimeSpanType : PrimitiveType, IVersionType, ILiteralType { - /// - public TimeSpanType() - : base(SqlTypeFactory.Int64) + private static readonly object ZeroObject = TimeSpan.Zero; + + public TimeSpanType() : base(SqlTypeFactory.Int64) { } /// - public override string Name - { - get { return "TimeSpan"; } - } + public override string Name => "TimeSpan"; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { @@ -38,23 +36,8 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return new TimeSpan(Convert.ToInt64(rs[name])); - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - /// - public override System.Type ReturnedClass - { - get { return typeof(TimeSpan); } - } + public override System.Type ReturnedClass => typeof(TimeSpan); public override void Set(DbCommand st, object value, int index, ISessionImplementor session) { @@ -98,10 +81,7 @@ public object StringToObject(string xml) return TimeSpan.Parse(xml); } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion @@ -116,19 +96,13 @@ public override object FromStringValue(string xml) return TimeSpan.Parse(xml); } - public override System.Type PrimitiveClass - { - get { return typeof(TimeSpan); } - } + public override System.Type PrimitiveClass => typeof(TimeSpan); - public override object DefaultValue - { - get { return TimeSpan.Zero; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return '\'' + ((TimeSpan)value).Ticks.ToString() + '\''; + return '\'' + ((TimeSpan)value).Ticks.ToString(CultureInfo.InvariantCulture) + '\''; } } } diff --git a/src/NHibernate/Type/TimeType.cs b/src/NHibernate/Type/TimeType.cs index be487f81cff..e50957e8e68 100644 --- a/src/NHibernate/Type/TimeType.cs +++ b/src/NHibernate/Type/TimeType.cs @@ -66,11 +66,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - public override System.Type ReturnedClass { get { return typeof(DateTime); } @@ -171,8 +166,6 @@ public override object DefaultValue } public override string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((DateTime)value).ToShortTimeString() + "'"; - } + => dialect.ToStringLiteral(((DateTime) value).ToShortTimeString(), SqlTypeFactory.GetAnsiString(50)); } } diff --git a/src/NHibernate/Type/TypeFactory.cs b/src/NHibernate/Type/TypeFactory.cs index 758353c48a4..0fd384d25c9 100644 --- a/src/NHibernate/Type/TypeFactory.cs +++ b/src/NHibernate/Type/TypeFactory.cs @@ -292,7 +292,9 @@ private static void RegisterDefaultNetTypes() RegisterType(typeof (Boolean), NHibernateUtil.Boolean, new[] { "boolean", "bool" }); RegisterType(typeof (Byte), NHibernateUtil.Byte, new[]{ "byte"}); RegisterType(typeof (Char), NHibernateUtil.Character, new[] {"character", "char"}); - RegisterType(typeof (CultureInfo), NHibernateUtil.CultureInfo, new[]{ "locale"}); + RegisterType(typeof (CultureInfo), NHibernateUtil.CultureInfo, new[] { "locale" }, + l => GetType(NHibernateUtil.CultureInfo, l, len => new CultureInfoType(SqlTypeFactory.GetString(len))), + false); RegisterType(typeof (DateTime), NHibernateUtil.DateTime, new[] { "datetime" }, s => GetType(NHibernateUtil.DateTime, s, scale => new DateTimeType(SqlTypeFactory.GetDateTime((byte)scale))), false); @@ -344,11 +346,10 @@ private static void RegisterDefaultNetTypes() } /// - /// Register other NO Default .NET type + /// Register types which are not a default for a .NET type. /// /// - /// These type will be used only when the "type" attribute was is specified in the mapping. - /// These are in here because needed to NO override default CLR types and be available in mappings + /// These types will be used only when the "type" attribute is specified in the mapping. /// private static void RegisterBuiltInTypes() { diff --git a/src/NHibernate/Type/TypeType.cs b/src/NHibernate/Type/TypeType.cs index 6d5b541257a..f19edaaabb0 100644 --- a/src/NHibernate/Type/TypeType.cs +++ b/src/NHibernate/Type/TypeType.cs @@ -46,26 +46,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return ParseStringRepresentation(NHibernateUtil.String.Get(rs, index, session)); } - /// - /// Gets the in the for the Property. - /// - /// The that contains the value. - /// The name of the field to get the value from. - /// The session for which the operation is done. - /// The from the database. - /// - /// This just calls gets the index of the name in the DbDataReader - /// and calls the overloaded version - /// (DbDataReader, Int32). - /// - /// - /// Thrown when the value in the database can not be loaded as a - /// - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// /// Puts the Assembly Qualified Name of the /// Property into to the . diff --git a/src/NHibernate/Type/UInt16Type.cs b/src/NHibernate/Type/UInt16Type.cs index 8628e8d4a91..4913c0fc792 100644 --- a/src/NHibernate/Type/UInt16Type.cs +++ b/src/NHibernate/Type/UInt16Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -16,18 +17,16 @@ namespace NHibernate.Type [Serializable] public partial class UInt16Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = (ushort) 0; + + /// public UInt16Type() : base(SqlTypeFactory.UInt16) { } /// - public override string Name - { - get { return "UInt16"; } - } + public override string Name => "UInt16"; - private static readonly UInt16 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,26 +43,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (ushort) bi, - var c => Convert.ToUInt16(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(UInt16); } - } + public override System.Type ReturnedClass => typeof(UInt16); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -104,26 +84,17 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt16); } - } + public override System.Type PrimitiveClass => typeof(UInt16); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((ushort)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UInt32Type.cs b/src/NHibernate/Type/UInt32Type.cs index 274d101b5ae..0f1a739e5ab 100644 --- a/src/NHibernate/Type/UInt32Type.cs +++ b/src/NHibernate/Type/UInt32Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -16,18 +17,16 @@ namespace NHibernate.Type [Serializable] public partial class UInt32Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0U; + + /// public UInt32Type() : base(SqlTypeFactory.UInt32) { } /// - public override string Name - { - get { return "UInt32"; } - } + public override string Name => "UInt32"; - private static readonly UInt32 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -44,26 +43,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (uint) bi, - var c => Convert.ToUInt32(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(UInt32); } - } + public override System.Type ReturnedClass => typeof(UInt32); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -104,26 +84,17 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt32); } - } + public override System.Type PrimitiveClass => typeof(UInt32); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((uint)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UInt64Type.cs b/src/NHibernate/Type/UInt64Type.cs index 83d710a47f3..333fd9b0dc6 100644 --- a/src/NHibernate/Type/UInt64Type.cs +++ b/src/NHibernate/Type/UInt64Type.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Globalization; using System.Numerics; using NHibernate.Engine; using NHibernate.SqlTypes; @@ -16,17 +17,15 @@ namespace NHibernate.Type [Serializable] public partial class UInt64Type : PrimitiveType, IDiscriminatorType, IVersionType { - /// + private static readonly object ZeroObject = 0UL; + + /// public UInt64Type() : base(SqlTypeFactory.UInt64) { } - public override string Name - { - get { return "UInt64"; } - } + public override string Name => "UInt64"; - private static readonly UInt32 ZERO = 0; public override object Get(DbDataReader rs, int index, ISessionImplementor session) { try @@ -43,26 +42,7 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi } } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - try - { - return rs[name] switch - { - BigInteger bi => (ulong) bi, - var c => Convert.ToUInt64(c) - }; - } - catch (Exception ex) - { - throw new FormatException(string.Format("Input string '{0}' was not in the correct format.", rs[name]), ex); - } - } - - public override System.Type ReturnedClass - { - get { return typeof(UInt64); } - } + public override System.Type ReturnedClass => typeof(UInt64); public override void Set(DbCommand rs, object value, int index, ISessionImplementor session) { @@ -103,26 +83,17 @@ public virtual object Seed(ISessionImplementor session) return 1; } - public IComparer Comparator - { - get { return Comparer.Default; } - } + public IComparer Comparator => Comparer.Default; #endregion - public override System.Type PrimitiveClass - { - get { return typeof(UInt64); } - } + public override System.Type PrimitiveClass => typeof(UInt64); - public override object DefaultValue - { - get { return ZERO; } - } + public override object DefaultValue => ZeroObject; public override string ObjectToSQLString(object value, Dialect.Dialect dialect) { - return value.ToString(); + return ((ulong)value).ToString(CultureInfo.InvariantCulture); } } } diff --git a/src/NHibernate/Type/UriType.cs b/src/NHibernate/Type/UriType.cs index 68f319606d3..59f9ec61238 100644 --- a/src/NHibernate/Type/UriType.cs +++ b/src/NHibernate/Type/UriType.cs @@ -54,11 +54,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi return StringToObject(Convert.ToString(rs[index])); } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return StringToObject(Convert.ToString(rs[name])); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { @@ -84,9 +79,7 @@ public override object FromStringValue(string xml) } public string ObjectToSQLString(object value, Dialect.Dialect dialect) - { - return "'" + ((Uri)value).OriginalString + "'"; - } + => dialect.ToStringLiteral(((Uri) value).OriginalString, SqlType); /// public override object Assemble(object cached, ISessionImplementor session, object owner) diff --git a/src/NHibernate/Type/XDocType.cs b/src/NHibernate/Type/XDocType.cs index fc29eaf478f..69912c8ec77 100644 --- a/src/NHibernate/Type/XDocType.cs +++ b/src/NHibernate/Type/XDocType.cs @@ -47,11 +47,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi #pragma warning restore 618 } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/Type/XmlDocType.cs b/src/NHibernate/Type/XmlDocType.cs index a138ee56b46..d4b26317f29 100644 --- a/src/NHibernate/Type/XmlDocType.cs +++ b/src/NHibernate/Type/XmlDocType.cs @@ -46,11 +46,6 @@ public override object Get(DbDataReader rs, int index, ISessionImplementor sessi #pragma warning restore 618 } - public override object Get(DbDataReader rs, string name, ISessionImplementor session) - { - return Get(rs, rs.GetOrdinal(name), session); - } - /// public override string ToLoggableString(object value, ISessionFactoryImplementor factory) { diff --git a/src/NHibernate/TypeMismatchException.cs b/src/NHibernate/TypeMismatchException.cs index 5e511d6dadc..d3568109f01 100644 --- a/src/NHibernate/TypeMismatchException.cs +++ b/src/NHibernate/TypeMismatchException.cs @@ -11,6 +11,8 @@ public class TypeMismatchException : HibernateException { public TypeMismatchException(string message) : base(message) { } public TypeMismatchException(string message, Exception inner) : base(message, inner) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected TypeMismatchException(SerializationInfo info,StreamingContext context): base(info, context) { } } } diff --git a/src/NHibernate/UnresolvableObjectException.cs b/src/NHibernate/UnresolvableObjectException.cs index d766bf2881a..75be1da8251 100644 --- a/src/NHibernate/UnresolvableObjectException.cs +++ b/src/NHibernate/UnresolvableObjectException.cs @@ -92,6 +92,9 @@ public static void ThrowIfNull(object o, object id, string entityName) #region ISerializable Members +#pragma warning disable CS0809 + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -100,9 +103,11 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("clazz", clazz); info.AddValue("entityName", entityName); } +#pragma warning restore CS0809 - protected UnresolvableObjectException(SerializationInfo info, StreamingContext context) - : base(info, context) + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] + protected UnresolvableObjectException(SerializationInfo info, StreamingContext context) : base(info, context) { identifier = info.GetValue("identifier", typeof(object)); clazz = info.GetValue("clazz", typeof(System.Type)) as System.Type; diff --git a/src/NHibernate/Util/CollectionHelper.cs b/src/NHibernate/Util/CollectionHelper.cs index e6ed9842065..6f40567923c 100644 --- a/src/NHibernate/Util/CollectionHelper.cs +++ b/src/NHibernate/Util/CollectionHelper.cs @@ -733,8 +733,9 @@ public static bool DictionaryEquals(IDictionary m1, IDictionary.Default) : m1.All(kv => m2.TryGetValue(kv.Key, out var value) && comparer.Equals(kv.Value, value))); +#if !NETCOREAPP2_0_OR_GREATER && !NETSTANDARD2_1_OR_GREATER //It's added to make use of optimized .NET Core Dictionary.Remove(key, out value) method - internal static bool Remove(this Dictionary dic, TKey key, out TValue value) + public static bool Remove(this Dictionary dic, TKey key, out TValue value) { if (!dic.TryGetValue(key, out value)) return false; @@ -742,6 +743,7 @@ internal static bool Remove(this Dictionary dic, TKe dic.Remove(key); return true; } +#endif private static bool? FastCheckEquality(IEnumerable c1, IEnumerable c2) { diff --git a/src/NHibernate/Util/JoinedEnumerable.cs b/src/NHibernate/Util/JoinedEnumerable.cs index 2e9d3ab6b50..5fedb70da46 100644 --- a/src/NHibernate/Util/JoinedEnumerable.cs +++ b/src/NHibernate/Util/JoinedEnumerable.cs @@ -8,6 +8,8 @@ namespace NHibernate.Util /// /// Concatenates multiple objects implementing into one. /// + // Since v5.6 + [Obsolete("This class has no more usages in NHibernate and will be removed in a future version.")] public class JoinedEnumerable : IEnumerable { private static readonly INHibernateLogger log = NHibernateLogger.For(typeof(JoinedEnumerable)); diff --git a/src/NHibernate/Util/LinkHashMap.cs b/src/NHibernate/Util/LinkHashMap.cs new file mode 100644 index 00000000000..26d3e147506 --- /dev/null +++ b/src/NHibernate/Util/LinkHashMap.cs @@ -0,0 +1,624 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.Serialization; +using System.Text; +using NHibernate.DebugHelpers; + +namespace NHibernate.Util +{ + /// + /// A map of objects whose mapping entries are sequenced based on the order in which they were + /// added. This data structure has fast O(1) search time, deletion time, and insertion time + /// + /// + /// This class is not thread safe. + /// This class is not really a replication of JDK LinkedHashMap{K, V}, + /// this class is an adaptation of SequencedHashMap with generics. + /// + [DebuggerTypeProxy(typeof(CollectionProxy<>))] + [Serializable] + internal class LinkHashMap : IDictionary, IDeserializationCallback + { + [Serializable] + protected class Entry + { + public Entry(TKey key, TValue value) + { + Key = key; + Value = value; + } + + public TKey Key { get; } + + public TValue Value { get; set; } + + public Entry Next { get; set; } + + public Entry Prev { get; set; } + + #region System.Object Members + + public override int GetHashCode() + { + return Key == null ? 0 : Key.GetHashCode(); + } + + public override bool Equals(object obj) + { + var other = obj as Entry; + if (other == null) return false; + if (other == this) return true; + + return (Key == null ? other.Key == null : Key.Equals(other.Key)) && + (Value == null ? other.Value == null : Value.Equals(other.Value)); + } + + public override string ToString() + { + return "[" + Key + "=" + Value + "]"; + } + + #endregion + } + + private readonly Entry _header; + private readonly Dictionary _entries; + private long _version; + + /// + /// Initializes a new instance of the class that is empty, + /// has the default initial capacity, and uses the default equality comparer for the key type. + /// + public LinkHashMap() + : this(0, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, + /// has the specified initial capacity, and uses the default equality comparer for the key type. + /// + /// The initial number of elements that the can contain. + public LinkHashMap(int capacity) + : this(capacity, null) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the default initial capacity, and uses the specified . + /// + /// The implementation to use when comparing keys, or null to use the default EqualityComparer for the type of the key. + public LinkHashMap(IEqualityComparer equalityComparer) + : this(0, equalityComparer) + { + } + + /// + /// Initializes a new instance of the class that is empty, has the specified initial capacity, and uses the specified . + /// + /// The initial number of elements that the can contain. + /// The implementation to use when comparing keys, or null to use the default EqualityComparer for the type of the key. + public LinkHashMap(int capacity, IEqualityComparer equalityComparer) + { + _header = CreateSentinel(); + _entries = new Dictionary(capacity, equalityComparer); + } + + #region IDictionary Members + + public virtual bool ContainsKey(TKey key) + { + return _entries.ContainsKey(key); + } + + public virtual void Add(TKey key, TValue value) + { + var e = new Entry(key, value); + _entries.Add(key, e); + _version++; + InsertEntry(e); + } + + public virtual bool Remove(TKey key) + { + return RemoveImpl(key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + var result = _entries.TryGetValue(key, out var entry); + if (result) + value = entry.Value; + else + value = default; + + return result; + } + + public TValue this[TKey key] + { + get + { + return _entries[key].Value; + } + set + { + if (_entries.TryGetValue(key, out var e)) + OverrideEntry(e, value); + else + Add(key, value); + } + } + + private void OverrideEntry(Entry e, TValue value) + { + _version++; + RemoveEntry(e); + e.Value = value; + InsertEntry(e); + } + + public KeyCollection Keys => new KeyCollection(this); + + ICollection IDictionary.Keys => new KeyCollection(this); + + public virtual ValueCollection Values => new ValueCollection(this); + + ICollection IDictionary.Values => new ValueCollection(this); + + #endregion + + #region ICollection> Members + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public virtual void Clear() + { + _version++; + + _entries.Clear(); + + _header.Next = _header; + _header.Prev = _header; + } + + public bool Contains(KeyValuePair item) + { + return Contains(item.Key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + foreach (var pair in this) + array.SetValue(pair, arrayIndex++); + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + public virtual int Count => _entries.Count; + + public virtual bool IsReadOnly => false; + + #endregion + + public Enumerator GetEnumerator() => new Enumerator(this); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return new Enumerator(this); + } + + #endregion + + #region IEnumerable> Members + + IEnumerator> IEnumerable>.GetEnumerator() + { + return new Enumerator(this); + } + + #endregion + + #region LinkHashMap Members + + private bool IsEmpty + { + get { return _header.Next == _header; } + } + + public virtual bool IsFixedSize => false; + + public virtual TKey FirstKey + { + get { return First == null ? default : First.Key; } + } + + public virtual TValue FirstValue + { + get { return First == null ? default : First.Value; } + } + + public virtual TKey LastKey + { + get { return Last == null ? default : Last.Key; } + } + + public virtual TValue LastValue + { + get { return Last == null ? default : Last.Value; } + } + + public virtual bool Contains(TKey key) + { + return ContainsKey(key); + } + + public virtual bool ContainsValue(TValue value) + { + if (value == null) + { + for (var entry = _header.Next; entry != _header; entry = entry.Next) + { + if (entry.Value == null) return true; + } + } + else + { + for (var entry = _header.Next; entry != _header; entry = entry.Next) + { + if (value.Equals(entry.Value)) return true; + } + } + return false; + } + + #endregion + + private static Entry CreateSentinel() + { + var s = new Entry(default, default); + s.Prev = s; + s.Next = s; + return s; + } + + private static void RemoveEntry(Entry entry) + { + entry.Next.Prev = entry.Prev; + entry.Prev.Next = entry.Next; + } + + private void InsertEntry(Entry entry) + { + entry.Next = _header; + entry.Prev = _header.Prev; + _header.Prev.Next = entry; + _header.Prev = entry; + } + + private Entry First + { + get { return IsEmpty ? null : _header.Next; } + } + + private Entry Last + { + get { return IsEmpty ? null : _header.Prev; } + } + + private bool RemoveImpl(TKey key) + { + if (!_entries.Remove(key, out var e)) + return false; + + _version++; + RemoveEntry(e); + return true; + } + + void IDeserializationCallback.OnDeserialization(object sender) + { + ((IDeserializationCallback)_entries).OnDeserialization(sender); + } + + #region System.Object Members + + public override string ToString() + { + var buf = new StringBuilder(); + buf.Append('['); + for (Entry pos = _header.Next; pos != _header; pos = pos.Next) + { + buf.Append(pos.Key); + buf.Append('='); + buf.Append(pos.Value); + if (pos.Next != _header) + { + buf.Append(','); + } + } + buf.Append(']'); + + return buf.ToString(); + } + + #endregion + + public class KeyCollection : ICollection + { + private readonly LinkHashMap _dictionary; + + public KeyCollection(LinkHashMap dictionary) + { + _dictionary = dictionary; + } + + #region ICollection Members + + void ICollection.Add(TKey item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + void ICollection.Clear() + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + bool ICollection.Contains(TKey item) + { + foreach (var key in this) + { + if (key.Equals(item)) + return true; + } + return false; + } + + public void CopyTo(TKey[] array, int arrayIndex) + { + foreach (var key in this) + array.SetValue(key, arrayIndex++); + } + + bool ICollection.Remove(TKey item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(KeyCollection)} is readonly."); + } + + public int Count => _dictionary.Count; + + bool ICollection.IsReadOnly => true; + + #endregion + + public Enumerator GetEnumerator() => new(_dictionary); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + public struct Enumerator : IEnumerator + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public TKey Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return _current.Key; + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } + + public class ValueCollection : ICollection + { + private readonly LinkHashMap _dictionary; + + public ValueCollection(LinkHashMap dictionary) + { + _dictionary = dictionary; + } + + #region ICollection Members + + void ICollection.Add(TValue item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + void ICollection.Clear() + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + bool ICollection.Contains(TValue item) + { + foreach (var value in this) + { + if (value.Equals(item)) + return true; + } + return false; + } + + public void CopyTo(TValue[] array, int arrayIndex) + { + foreach (var value in this) + array.SetValue(value, arrayIndex++); + } + + bool ICollection.Remove(TValue item) + { + throw new NotSupportedException($"{nameof(LinkHashMap)}+{nameof(ValueCollection)} is readonly."); + } + + public int Count => _dictionary.Count; + + bool ICollection.IsReadOnly => true; + + #endregion + + public Enumerator GetEnumerator() => new Enumerator(_dictionary); + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() => new Enumerator(_dictionary); + + #endregion + + public struct Enumerator : IEnumerator + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public TValue Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return _current.Value; + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } + + public struct Enumerator : IEnumerator> + { + private readonly LinkHashMap _dictionary; + private Entry _current; + private readonly long _version; + + public Enumerator(LinkHashMap dictionary) + { + _dictionary = dictionary; + _version = dictionary._version; + _current = dictionary._header; + } + + public bool MoveNext() + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + if (_current.Next == _dictionary._header) + return false; + + _current = _current.Next; + + return true; + } + + public KeyValuePair Current + { + get + { + if (_dictionary._version != _version) + throw new InvalidOperationException("Enumerator was modified"); + + return new KeyValuePair(_current.Key, _current.Value); + } + } + + object IEnumerator.Current => Current; + + void IEnumerator.Reset() + { + _current = _dictionary._header; + } + + void IDisposable.Dispose() { } + } + } +} diff --git a/src/NHibernate/Util/LinkedHashMap.cs b/src/NHibernate/Util/LinkedHashMap.cs index 5487204deee..e2ce34b60f2 100644 --- a/src/NHibernate/Util/LinkedHashMap.cs +++ b/src/NHibernate/Util/LinkedHashMap.cs @@ -19,6 +19,8 @@ namespace NHibernate.Util /// [DebuggerTypeProxy(typeof(CollectionProxy<>))] [Serializable] + // Since 5.6 + [Obsolete("This class has no more usages and will be removed in a future version.")] public class LinkedHashMap : IDictionary, IDeserializationCallback { [Serializable] diff --git a/src/NHibernate/Util/ReflectHelper.cs b/src/NHibernate/Util/ReflectHelper.cs index 06352101745..b693956de95 100644 --- a/src/NHibernate/Util/ReflectHelper.cs +++ b/src/NHibernate/Util/ReflectHelper.cs @@ -391,6 +391,8 @@ public static IGetter GetGetter(System.Type theClass, string propertyName, strin /// /// The NHibernate for the named property. /// + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public static IType ReflectedPropertyType(System.Type theClass, string name, string access) { System.Type propertyClass = ReflectedPropertyClass(theClass, name, access); @@ -419,6 +421,8 @@ public static System.Type ReflectedPropertyClass(System.Type theClass, string na /// The name of the property/field to find in the class. /// The name of the property accessor for the property. /// The for the named property. + // Since v5.6 + [Obsolete("This method is not used and will be removed in a future version")] public static System.Type ReflectedPropertyClass(string className, string name, string accessorName) { try @@ -820,31 +824,18 @@ private static MethodInfo SafeGetMethod(System.Type type, MethodInfo method, Sys return foundMethod; } - internal static object GetConstantValue(string qualifiedName) - { - return GetConstantValue(qualifiedName, null); - } - internal static object GetConstantValue(string qualifiedName, ISessionFactoryImplementor sfi) { string className = StringHelper.Qualifier(qualifiedName); - if (!string.IsNullOrEmpty(className)) - { - System.Type t = System.Type.GetType(className); - - if (t == null && sfi != null) - { - t = System.Type.GetType(sfi.GetImportedClassName(className)); - } + if (string.IsNullOrEmpty(className)) + return null; - if (t != null) - { - return GetConstantValue(t, StringHelper.Unqualify(qualifiedName)); - } - } + var t = System.Type.GetType(sfi?.GetImportedClassName(className) ?? className); - return null; + return t == null + ? null + : GetConstantValue(t, StringHelper.Unqualify(qualifiedName)); } // Since v5 diff --git a/src/NHibernate/Util/ReflectionCache.cs b/src/NHibernate/Util/ReflectionCache.cs index 47fde15950d..45f97559780 100644 --- a/src/NHibernate/Util/ReflectionCache.cs +++ b/src/NHibernate/Util/ReflectionCache.cs @@ -232,5 +232,11 @@ internal static class TypeMethods internal static readonly MethodInfo GetTypeFromHandle = ReflectHelper.FastGetMethod(System.Type.GetTypeFromHandle, default(RuntimeTypeHandle)); } + + internal static class ObjectMethods + { + internal static readonly MethodInfo Finalize = + typeof(object).GetMethod("Finalize", BindingFlags.NonPublic | BindingFlags.Instance); + } } } diff --git a/src/NHibernate/Util/StringHelper.cs b/src/NHibernate/Util/StringHelper.cs index 7372d79f639..8b29f178300 100644 --- a/src/NHibernate/Util/StringHelper.cs +++ b/src/NHibernate/Util/StringHelper.cs @@ -871,5 +871,15 @@ public static bool IsAnyNewLine(this string str, int index, out int newLineLengt newLineLength = 0; return false; } + + internal static string GenerateSuffix(int index) + { + return index switch + { + 0 => "0_", + 1 => "1_", + _ => string.Intern(index.ToString() + Underscore) + }; + } } } diff --git a/src/NHibernate/Util/TypeNameParser.cs b/src/NHibernate/Util/TypeNameParser.cs index 6a56f862fb0..5d90c7bb4b5 100644 --- a/src/NHibernate/Util/TypeNameParser.cs +++ b/src/NHibernate/Util/TypeNameParser.cs @@ -12,6 +12,8 @@ public class ParserException : Exception { public ParserException(string message) : base(message) { } + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected ParserException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/src/NHibernate/WrongClassException.cs b/src/NHibernate/WrongClassException.cs index 90c7f1024dc..3018636d031 100644 --- a/src/NHibernate/WrongClassException.cs +++ b/src/NHibernate/WrongClassException.cs @@ -69,12 +69,15 @@ public override string Message /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] protected WrongClassException(SerializationInfo info, StreamingContext context) : base(info, context) { entityName = info.GetValue("entityName", typeof(string)) as string; identifier = info.GetValue("identifier", typeof(object)); } +#pragma warning disable CS0809 /// /// Sets the serialization info for after /// getting the info from the base Exception. @@ -86,6 +89,8 @@ protected WrongClassException(SerializationInfo info, StreamingContext context) /// /// The that contains contextual information about the source or destination. /// + // Since v5.6 + [Obsolete("This API supports obsolete formatter-based serialization and will be removed in a future version")] [SecurityCritical] public override void GetObjectData(SerializationInfo info, StreamingContext context) { @@ -93,6 +98,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont info.AddValue("entityName", entityName, typeof(string)); info.AddValue("identifier", identifier, typeof(object)); } +#pragma warning restore CS0809 #endregion } diff --git a/src/NHibernate/nhibernate-configuration.xsd b/src/NHibernate/nhibernate-configuration.xsd index 08d922ad963..4c6390bbea8 100644 --- a/src/NHibernate/nhibernate-configuration.xsd +++ b/src/NHibernate/nhibernate-configuration.xsd @@ -176,6 +176,14 @@ + + + + Indicates if the database needs to have backslash escaped in string literals. The default is + dialect dependent. + + + @@ -233,12 +241,32 @@ after scope disposal. This occurs when the transaction is distributed. This notably concerns ISessionImplementor.AfterTransactionCompletion(bool, ITransaction). NHibernate protects the session from being concurrently used by the code following the scope disposal - with a lock. To prevent any application freeze, this lock has a default timeout of five seconds. If the - application appears to require longer (!) running transaction completion events, this setting allows to + with a lock. To prevent any application freeze, this lock has a default timeout of one second. If the + application appears to require longer running transaction completion events, this setting allows to raise this timeout. -1 disables the timeout. + + + + Whether session synchronisation failures occuring during finalizations of system transaction should be + ignored or not. false by default. + + When a system transaction terminates abnormaly, especially through timeouts, it may have its + completion events running on concurrent threads while the session is still performing some processing. + To prevent threading concurrency failures, NHibernate then wait for the session to end its processing, + up to transaction.system_completion_lock_timeout. If the session processing is still ongoing + afterwards, it will by default log an error, perform transaction finalization processing concurrently, + then throw a synchronization error. This setting allows to disable that later throw. + + Disabling the throw can be useful if the used data provider has its own locking mechanism applied + during transaction completion, preventing the session to end its processing. It may then be safe to + ignore this synchronization failure. In case of threading concurrency failure, you may then need to + raise transaction.system_completion_lock_timeout. + + + diff --git a/teamcity.build b/teamcity.build index 7e90e13e430..0d2955c26b7 100644 --- a/teamcity.build +++ b/teamcity.build @@ -50,6 +50,8 @@ + +