From 3739000fb38eac0de294fef30361db3d6cbbdf19 Mon Sep 17 00:00:00 2001 From: Jiri Cincura Date: Sat, 18 Feb 2023 14:41:49 +0100 Subject: [PATCH] EFCore 7.0 and around --- .github/workflows/ci.yml | 4 +- header.ps1 | 2 +- include.ps1 | 2 +- .../EntityFramework.Firebird.Tests.csproj | 7 +- .../EntityFrameworkTestsBase.cs | 2 +- .../EntityFramework.Firebird.csproj | 2 +- .../SqlGen/SqlGenerator.cs | 2 +- ...rebirdSql.Data.FirebirdClient.Tests.csproj | 4 +- .../FirebirdSql.Data.FirebirdClient.csproj | 6 +- .../Logging/LogMessages.cs | 2 +- ...meworkCore.Firebird.FunctionalTests.csproj | 5 +- .../Helpers/ModelHelpers.cs | 36 +- .../Helpers/SkippingAttributes.cs | 15 + .../Helpers/Xunit.cs | 21 +- .../MigrationsFbTest.cs | 44 +- ...omplexNavigationsCollectionsQueryFbTest.cs | 198 ++++++++ ...gationsCollectionsSharedTypeQueryFbTest.cs | 184 +++++++ ...xNavigationsCollectionsSplitQueryFbTest.cs | 198 ++++++++ ...nsCollectionsSplitSharedTypeQueryFbTest.cs | 149 ++++++ .../Query/ComplexNavigationsQueryFbTest.cs | 94 +++- ...lexNavigationsSharedTypeQueryFbFixture.cs} | 10 +- ...ComplexNavigationsSharedTypeQueryFbTest.cs | 91 ++++ .../Query/CompositeKeysQueryFbFixture.cs | 35 ++ .../Query/CompositeKeysQueryFbTest.cs | 30 ++ .../Query/CompositeKeysSplitQueryFbTest.cs | 29 ++ .../Query/Ef6GroupByFbTest.cs | 58 +++ .../Query/EntitySplittingQueryFbTest.cs | 27 ++ .../Query/FromSqlQueryFbTest.cs | 20 +- .../Query/GearsOfWarQueryFbTest.cs | 19 +- .../ManyToManyHeterogeneousQueryFbTest.cs | 27 ++ .../Query/ManyToManyNoTrackingQueryFbTest.cs | 7 + .../Query/ManyToManyQueryFbFixture.cs | 8 + .../Query/ManyToManyQueryFbTest.cs | 7 + .../NorthwindAggregateOperatorsQueryFbTest.cs | 75 +++ .../NorthwindEFPropertyIncludeQueryFbTest.cs | 146 ++++++ .../Query/NorthwindFunctionsQueryFbTest.cs | 285 +++++++++++ .../Query/NorthwindGroupByQueryFbTest.cs | 19 +- .../NorthwindIncludeNoTrackingQueryFbTest.cs | 158 ++++++ .../Query/NorthwindIncludeQueryFbTest.cs | 14 + .../Query/NorthwindJoinQueryFbTest.cs | 117 +++++ .../NorthwindKeylessEntitiesQueryFbTest.cs | 65 +++ .../NorthwindMiscellaneousQueryFbTest.cs | 136 ++++++ .../Query/NorthwindQueryFbFixture.cs | 2 + .../Query/NorthwindSelectQueryFbTest.cs | 49 ++ .../NorthwindSetOperationsQueryFbTest.cs | 111 +++++ ...thwindSplitIncludeNoTrackingQueryFbTest.cs | 105 ++++ .../Query/NorthwindSplitIncludeQueryFbTest.cs | 105 ++++ .../Query/NorthwindSqlQueryFbTest.cs | 33 ++ .../NorthwindStringIncludeQueryFbTest.cs | 144 ++++++ .../Query/NorthwindWhereQueryFbTest.cs | 70 +++ .../Query/OwnedEntityQueryFbTest.cs | 37 ++ .../Query/OwnedQueryFbTest.cs | 35 ++ .../Query/QueryFilterFuncletizationFbTest.cs | 238 ++++++++++ .../Query/QueryNoClientEvalFbTest.cs | 5 +- .../Query/SharedTypeQueryFbTest.cs | 27 ++ .../Query/SimpleQueryFbTest.cs | 81 ++++ ...=> TPCFiltersInheritanceQueryFbFixture.cs} | 8 +- .../Query/TPCFiltersInheritanceQueryFbTest.cs | 28 ++ .../Query/TPCGearsOfWarQueryFbFixture.cs | 46 ++ .../Query/TPCGearsOfWarQueryFbTest.cs | 448 ++++++++++++++++++ .../Query/TPCInheritanceQueryFbFixture.cs | 23 + .../Query/TPCInheritanceQueryFbFixtureBase.cs | 27 ++ .../Query/TPCInheritanceQueryFbTest.cs | 25 + .../Query/TPCInheritanceQueryFbTestBase.cs | 29 ++ .../Query/TPCInheritanceQueryHiLoFbFixture.cs | 32 ++ .../Query/TPCInheritanceQueryHiLoFbTest.cs | 25 + .../TPCManyToManyNoTrackingQueryFbTest.cs | 51 ++ .../Query/TPCManyToManyQueryFbFixture.cs | 35 ++ .../Query/TPCManyToManyQueryFbTest.cs | 51 ++ .../Query/TPCRelationshipsQueryFbTest.cs | 34 ++ .../TPTFiltersInheritanceQueryFbFixture.cs | 10 +- .../Query/TPTFiltersInheritanceQueryFbTest.cs | 6 - .../Query/TPTGearsOfWarQueryFbTest.cs | 24 +- .../Query/TPTInheritanceQueryFbFixture.cs | 9 + .../TPTManyToManyNoTrackingQueryFbTest.cs | 7 + .../Query/TPTManyToManyQueryFbFixture.cs | 8 + .../Query/TPTManyToManyQueryFbTest.cs | 7 + .../Query/ToSqlQueryFbTest.cs | 110 +++++ .../Query/WarningsFbTest.cs | 5 +- .../TestUtilities/FbTestHelpers.cs | 4 +- .../TestUtilities/FbTestStore.cs | 15 +- .../UpdatesFbTest.cs | 24 +- ....EntityFrameworkCore.Firebird.Tests.csproj | 4 +- .../Extensions/FbDatabaseFacadeExtensions.cs | 22 +- .../Extensions/FbModelBuilderExtensions.cs | 34 ++ .../Extensions/FbModelExtensions.cs | 51 ++ .../Extensions/FbPropertyBuilderExtensions.cs | 37 ++ .../Extensions/FbPropertyExtensions.cs | 262 +++++++++- .../FbServiceCollectionExtensions.cs | 7 + ...irdSql.EntityFrameworkCore.Firebird.csproj | 5 +- .../Internal/FbModelValidator.cs | 43 ++ .../Conventions/FbConventionSetBuilder.cs | 20 +- .../FbStoreGenerationConvention.cs | 23 +- .../Metadata/FbValueGenerationStrategy.cs | 1 + .../Metadata/Internal/FbAnnotationNames.cs | 5 + .../Migrations/FbMigrationsSqlGenerator.cs | 50 ++ .../Internal/FbConvertTranslator.cs | 2 +- .../Internal/FbStringContainsTranslator.cs | 4 +- .../Internal/FbStringEndsWithTranslator.cs | 4 +- .../FbStringFirstOrDefaultTranslator.cs | 2 +- .../Internal/FbStringIndexOfTranslator.cs | 22 +- .../FbStringIsNullOrWhiteSpaceTranslator.cs | 5 +- .../FbStringLastOrDefaultTranslator.cs | 2 +- .../Internal/FbStringStartsWithTranslator.cs | 4 +- .../Query/Internal/FbQuerySqlGenerator.cs | 24 + .../Internal/FbProviderCodeGenerator.cs | 6 +- .../Storage/Internal/FbDatabaseCreator.cs | 2 +- .../Storage/Internal/FbSqlGenerationHelper.cs | 2 +- .../Storage/Internal/FbTypeMappingSource.cs | 76 +-- .../Update/Internal/FbUpdateSqlGenerator.cs | 33 +- .../Utilities/EnumerableMethods.cs | 374 +++++---------- .../Utilities/SharedTypeExtensions.cs | 160 +++---- .../Utilities/StringBuilderExtensions.cs | 4 +- .../Internal/FbSequenceHiLoValueGenerator.cs | 81 ++++ .../FbSequenceValueGeneratorFactory.cs | 91 ++++ .../Internal/FbSequenceValueGeneratorState.cs | 32 ++ .../Internal/FbValueGeneratorCache.cs | 57 +++ .../Internal/FbValueGeneratorSelector.cs | 99 ++++ .../IFbSequenceValueGeneratorFactory.cs | 30 ++ .../Internal/IFbValueGeneratorCache.cs | 27 ++ src/Perf/Perf.csproj | 2 +- src/Scratchpad/Program.cs | 2 +- src/Scratchpad/Scratchpad.csproj | 2 +- 123 files changed, 5619 insertions(+), 587 deletions(-) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/{UpdatesFbFixture.cs => Query/ComplexNavigationsSharedTypeQueryFbFixture.cs} (76%) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysSplitQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/Ef6GroupByFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/EntitySplittingQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyHeterogeneousQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindKeylessEntitiesQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSetOperationsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSqlQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindStringIncludeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedEntityQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SharedTypeQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SimpleQueryFbTest.cs rename src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/{QueryNoClientEvalFbFixture.cs => TPCFiltersInheritanceQueryFbFixture.cs} (83%) create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixtureBase.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyNoTrackingQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbFixture.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCRelationshipsQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ToSqlQueryFbTest.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceHiLoValueGenerator.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorFactory.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorState.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbSequenceValueGeneratorFactory.cs create mode 100644 src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbValueGeneratorCache.cs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b8857acd..03d7db98b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,10 +19,10 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - name: .NET 6.0 + - name: .NET 7.0 uses: actions/setup-dotnet@v1 with: - dotnet-version: 6.0.x + dotnet-version: 7.0.x - name: Build run: | diff --git a/header.ps1 b/header.ps1 index 936e531d9..2764a02c9 100644 --- a/header.ps1 +++ b/header.ps1 @@ -32,7 +32,7 @@ gci $baseDir -Recurse -Filter *.cs | %{ } } if (!$started) { - //echo $_.FullName + #echo $_.FullName return } diff --git a/include.ps1 b/include.ps1 index e3b4232e2..3031b02bc 100644 --- a/include.ps1 +++ b/include.ps1 @@ -7,5 +7,5 @@ function Check-ExitCode() { } function Get-UsedTargetFramework() { - return 'net6.0' + return 'net7.0' } \ No newline at end of file diff --git a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj index 3275dd0c1..1e04b33f4 100644 --- a/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj +++ b/src/EntityFramework.Firebird.Tests/EntityFramework.Firebird.Tests.csproj @@ -1,6 +1,7 @@  - net6.0 + + net7.0 false false true @@ -11,7 +12,7 @@ Exe FirebirdSql.Data.TestsBase.Program - + @@ -25,7 +26,7 @@ - + diff --git a/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs b/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs index 637780c75..cc8936ad0 100644 --- a/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs +++ b/src/EntityFramework.Firebird.Tests/EntityFrameworkTestsBase.cs @@ -27,7 +27,7 @@ public abstract class EntityFrameworkTestsBase : FbTestsBase { static EntityFrameworkTestsBase() { -#if NET6_0_OR_GREATER +#if !NETFRAMEWORK System.Data.Common.DbProviderFactories.RegisterFactory(FbProviderServices.ProviderInvariantName, FirebirdClientFactory.Instance); #endif DbConfiguration.SetConfiguration(new FbTestDbContext.Conf()); diff --git a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj index a1101bd8b..a2bb42363 100644 --- a/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj +++ b/src/EntityFramework.Firebird/EntityFramework.Firebird.csproj @@ -10,7 +10,7 @@ NETProvider - Entity Framework Provider - (c) 2014-2021 + (c) 2014-2023 EntityFramework.Firebird diff --git a/src/EntityFramework.Firebird/SqlGen/SqlGenerator.cs b/src/EntityFramework.Firebird/SqlGen/SqlGenerator.cs index cfdf24ba1..a97fb1a42 100644 --- a/src/EntityFramework.Firebird/SqlGen/SqlGenerator.cs +++ b/src/EntityFramework.Firebird/SqlGen/SqlGenerator.cs @@ -2552,7 +2552,7 @@ private static ISqlFragment HandleCanonicalFunctionBitwiseAnd(SqlGenerator sqlge private static ISqlFragment HandleCanonicalFunctionBitwiseNot(SqlGenerator sqlgen, DbFunctionExpression e) { - throw new NotSupportedException("BitwiseNot is not supported by Firebird."); + return sqlgen.HandleFunctionDefaultGivenName(e, "BIN_NOT"); } private static ISqlFragment HandleCanonicalFunctionBitwiseOr(SqlGenerator sqlgen, DbFunctionExpression e) diff --git a/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj b/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj index dd8ba1487..9ca84ea94 100644 --- a/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj +++ b/src/FirebirdSql.Data.FirebirdClient.Tests/FirebirdSql.Data.FirebirdClient.Tests.csproj @@ -1,6 +1,6 @@  - net6.0 + net7.0 false false true @@ -22,6 +22,6 @@ - + diff --git a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj index 173c08203..4aae158c3 100644 --- a/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj +++ b/src/FirebirdSql.Data.FirebirdClient/FirebirdSql.Data.FirebirdClient.csproj @@ -1,6 +1,6 @@  - net48;netstandard2.0;netstandard2.1;net5.0;net6.0 + net48;netstandard2.0;netstandard2.1;net5.0;net6.0;net7.0 FirebirdSql.Data.FirebirdClient FirebirdSql.Data true @@ -11,7 +11,7 @@ NETProvider - ADO.NET Data Provider - (c) 2002-2021 + (c) 2002-2023 FirebirdSql.Data.FirebirdClient @@ -51,6 +51,8 @@ + + all diff --git a/src/FirebirdSql.Data.FirebirdClient/Logging/LogMessages.cs b/src/FirebirdSql.Data.FirebirdClient/Logging/LogMessages.cs index 3d03d51ff..e21b5227c 100644 --- a/src/FirebirdSql.Data.FirebirdClient/Logging/LogMessages.cs +++ b/src/FirebirdSql.Data.FirebirdClient/Logging/LogMessages.cs @@ -286,4 +286,4 @@ public static void TransactionRolledBackRetaining(IFbLogger log, FbTransaction t } static bool IsNullParameterValue(object value) => value == DBNull.Value || value == null; -} \ No newline at end of file +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj index 23e8d2083..38b0392aa 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.csproj @@ -1,6 +1,6 @@  - net6.0 + net7.0 false false true @@ -8,9 +8,10 @@ FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests true ..\FirebirdSql.Data.TestsBase\FirebirdSql.Data.TestsBase.snk + true - + diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs index 028fe9095..f2d9b2371 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/ModelHelpers.cs @@ -47,14 +47,23 @@ public static void SimpleTableNames(ModelBuilder modelBuilder) { if (entityType.BaseType != null) continue; - var name = new string(entityType.GetTableName().Where(char.IsUpper).ToArray()); + entityType.SetTableName(Simplify(entityType.GetTableName())); + foreach (var property in entityType.GetProperties()) + { + property.SetColumnName(Simplify(property.Name)); + } + } + + string Simplify(string name) + { + name = new string(name.Where(char.IsUpper).ToArray()); var cnt = 1; while (names.Contains(name)) { name += cnt++; } names.Add(name); - entityType.SetTableName(name); + return name; } } @@ -76,4 +85,27 @@ public static void SetPrimaryKeyGeneration(ModelBuilder modelBuilder, FbValueGen } } } + + public static void ShortenMM(ModelBuilder modelBuilder) + { + foreach (var entityType in modelBuilder.Model.GetEntityTypes()) + { + entityType.SetTableName(Shorten(entityType.ShortName())); + foreach (var property in entityType.GetProperties()) + { + property.SetColumnName(Shorten(property.Name)); + } + } + + static string Shorten(string s) + { + return s + .Replace("UnidirectionalEntity", "UE") + .Replace("Unidirectional", "U") + .Replace("JoinOneToThree", "J1_3") + .Replace("EntityTableSharing", "ETS") + .Replace("GeneratedKeys", "GK") + .Replace("ImplicitManyToMany", "IMM"); + } + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/SkippingAttributes.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/SkippingAttributes.cs index 49447be7c..a1d32b14b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/SkippingAttributes.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/SkippingAttributes.cs @@ -93,3 +93,18 @@ public LongExecutionTheoryAttribute() Skip = "Long execution."; } } + +public class NotSupportedByProviderFactAttribute : FactAttribute +{ + public NotSupportedByProviderFactAttribute() + { + Skip = "Not supported by provider."; + } +} +public class NotSupportedByProviderTheoryAttribute : TheoryAttribute +{ + public NotSupportedByProviderTheoryAttribute() + { + Skip = "Not supported by provider."; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/Xunit.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/Xunit.cs index 7db84979b..66091155d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/Xunit.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Helpers/Xunit.cs @@ -1,3 +1,20 @@ -using Xunit; +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ -[assembly: CollectionBehavior(DisableTestParallelization = true)] \ No newline at end of file +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Xunit; + +[assembly: CollectionBehavior(DisableTestParallelization = true)] diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs index b78f4ba9e..d27631822 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/MigrationsFbTest.cs @@ -204,18 +204,12 @@ public MigrationsFbTest(MigrationsFbFixture fixture) [Fact(Skip = SkipReason)] public override Task Rename_index() => base.Rename_index(); - [Fact(Skip = SkipReason)] - public override Task Add_primary_key() => base.Add_primary_key(); - [Fact(Skip = SkipReason)] public override Task Add_primary_key_with_name() => base.Add_primary_key_with_name(); [Fact(Skip = SkipReason)] public override Task Add_primary_key_composite_with_name() => base.Add_primary_key_composite_with_name(); - [Fact(Skip = SkipReason)] - public override Task Drop_primary_key() => base.Drop_primary_key(); - [Fact(Skip = SkipReason)] public override Task Add_foreign_key() => base.Add_foreign_key(); @@ -294,13 +288,49 @@ public MigrationsFbTest(MigrationsFbFixture fixture) [Fact(Skip = SkipReason)] public override Task SqlOperation() => base.SqlOperation(); + [Fact(Skip = SkipReason)] + public override Task Add_primary_key_int() => base.Add_primary_key_int(); + + [Fact(Skip = SkipReason)] + public override Task Add_primary_key_string() => base.Add_primary_key_string(); + + [Fact(Skip = SkipReason)] + public override Task Alter_column_change_computed_recreates_indexes() => base.Alter_column_change_computed_recreates_indexes(); + + [Fact(Skip = SkipReason)] + public override Task Alter_column_make_required_with_null_data() => base.Alter_column_make_required_with_null_data(); + + [Fact(Skip = SkipReason)] + public override Task Alter_index_change_sort_order() => base.Alter_index_change_sort_order(); + + [Fact(Skip = SkipReason)] + public override Task Alter_index_make_unique() => base.Alter_index_make_unique(); + + [Fact(Skip = SkipReason)] + public override Task Create_index_descending() => base.Create_index_descending(); + + [Fact(Skip = SkipReason)] + public override Task Create_index_descending_mixed() => base.Create_index_descending_mixed(); + + [Fact(Skip = SkipReason)] + public override Task Create_sequence_long() => base.Create_sequence_long(); + + [Fact(Skip = SkipReason)] + public override Task Create_sequence_short() => base.Create_sequence_short(); + + [Fact(Skip = SkipReason)] + public override Task Drop_primary_key_int() => base.Drop_primary_key_int(); + + [Fact(Skip = SkipReason)] + public override Task Drop_primary_key_string() => base.Drop_primary_key_string(); + public class MigrationsFbFixture : MigrationsFixtureBase { protected override string StoreName => nameof(MigrationsFbTest); protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; - public override TestHelpers TestHelpers => FbTestHelpers.Instance; + public override RelationalTestHelpers TestHelpers => FbTestHelpers.Instance; protected override IServiceCollection AddServices(IServiceCollection serviceCollection) #pragma warning disable EF1001 diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsQueryFbTest.cs new file mode 100644 index 000000000..4988b39d8 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsQueryFbTest.cs @@ -0,0 +1,198 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexNavigationsCollectionsQueryFbTest : ComplexNavigationsCollectionsQueryRelationalTestBase +{ + public ComplexNavigationsCollectionsQueryFbTest(ComplexNavigationsQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_issue_21665(bool async) + { + return base.Complex_query_issue_21665(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_after_different_filtered_include_different_level(bool async) + { + return base.Filtered_include_after_different_filtered_include_different_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async) + { + return base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter1(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(bool async) + { + return base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_outer_parameter_used_inside_filter(bool async) + { + return base.Filtered_include_outer_parameter_used_inside_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async) + { + return base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(bool async) + { + return base.Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_inside_subquery(bool async) + { + return base.Include_inside_subquery(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(bool async) + { + return base.SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Distinct_on_grouping_element(bool async) + { + return base.Skip_Take_Distinct_on_grouping_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) + { + return base.Skip_Take_on_grouping_element_inside_collection_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_collection_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_collection_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_reference_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_reference_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Select_collection_Skip_Take(bool async) + { + return base.Skip_Take_Select_collection_Skip_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Take_Select_collection_Take(bool async) + { + return base.Take_Select_collection_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Take_with_another_Take_on_top_level(bool async) + { + return base.Filtered_include_Take_with_another_Take_on_top_level(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryFbTest.cs new file mode 100644 index 000000000..35db72ca7 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSharedTypeQueryFbTest.cs @@ -0,0 +1,184 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexNavigationsCollectionsSharedTypeQueryFbTest : ComplexNavigationsCollectionsSharedTypeQueryRelationalTestBase +{ + public ComplexNavigationsCollectionsSharedTypeQueryFbTest(ComplexNavigationsSharedTypeQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Should fail, but not failing.")] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_navigation_and_Distinct_projecting_columns_including_join_key(bool async) + { + return base.SelectMany_with_navigation_and_Distinct_projecting_columns_including_join_key(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_after_different_filtered_include_different_level(bool async) + { + return base.Filtered_include_after_different_filtered_include_different_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async) + { + return base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter1(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(bool async) + { + return base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async) + { + return base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(bool async) + { + return base.Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Take_with_another_Take_on_top_level(bool async) + { + return base.Filtered_include_Take_with_another_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(bool async) + { + return base.SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Distinct_on_grouping_element(bool async) + { + return base.Skip_Take_Distinct_on_grouping_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) + { + return base.Skip_Take_on_grouping_element_inside_collection_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_collection_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_collection_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_reference_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_reference_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Select_collection_Skip_Take(bool async) + { + return base.Skip_Take_Select_collection_Skip_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Take_Select_collection_Take(bool async) + { + return base.Take_Select_collection_Take(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryFbTest.cs new file mode 100644 index 000000000..eb090f0c9 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitQueryFbTest.cs @@ -0,0 +1,198 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexNavigationsCollectionsSplitQueryFbTest : ComplexNavigationsCollectionsSplitQueryRelationalTestBase +{ + public ComplexNavigationsCollectionsSplitQueryFbTest(ComplexNavigationsQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_issue_21665(bool async) + { + return base.Complex_query_issue_21665(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_after_different_filtered_include_different_level(bool async) + { + return base.Filtered_include_after_different_filtered_include_different_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async) + { + return base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter1(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter1(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_complex_three_level_with_middle_having_filter2(bool async) + { + return base.Filtered_include_complex_three_level_with_middle_having_filter2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(bool async) + { + return base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_outer_parameter_used_inside_filter(bool async) + { + return base.Filtered_include_outer_parameter_used_inside_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async) + { + return base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(bool async) + { + return base.Filtered_include_Skip_Take_with_another_Skip_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_inside_subquery(bool async) + { + return base.Include_inside_subquery(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(bool async) + { + return base.SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Distinct_on_grouping_element(bool async) + { + return base.Skip_Take_Distinct_on_grouping_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) + { + return base.Skip_Take_on_grouping_element_inside_collection_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_collection_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_collection_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_reference_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_reference_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Select_collection_Skip_Take(bool async) + { + return base.Skip_Take_Select_collection_Skip_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Take_Select_collection_Take(bool async) + { + return base.Take_Select_collection_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Take_with_another_Take_on_top_level(bool async) + { + return base.Filtered_include_Take_with_another_Take_on_top_level(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs new file mode 100644 index 000000000..e5641d09e --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest.cs @@ -0,0 +1,149 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest : ComplexNavigationsCollectionsSplitSharedTypeQueryRelationalTestBase +{ + public ComplexNavigationsCollectionsSplitSharedTypeQueryFbTest(ComplexNavigationsSharedTypeQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Should fail, but not failing.")] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_navigation_and_Distinct_projecting_columns_including_join_key(bool async) + { + return base.SelectMany_with_navigation_and_Distinct_projecting_columns_including_join_key(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(bool async) + { + return base.Complex_query_with_let_collection_projection_FirstOrDefault_with_ToList_on_inner_and_outer(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(bool async) + { + return base.Filtered_include_and_non_filtered_include_followed_by_then_include_on_same_navigation(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(bool async) + { + return base.Filtered_include_multiple_multi_level_includes_with_first_level_using_filter_include_on_one_of_the_chains_only(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(bool async) + { + return base.Filtered_include_same_filter_set_on_same_navigation_twice_followed_by_ThenIncludes(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_Take_with_another_Take_on_top_level(bool async) + { + return base.Filtered_include_Take_with_another_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_FirstOrDefault_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(bool async) + { + return base.Filtered_include_with_Take_without_order_by_followed_by_ThenInclude_and_unordered_Take_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(bool async) + { + return base.Projecting_collection_with_group_by_after_optional_reference_correlated_with_parent(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(bool async) + { + return base.SelectMany_with_predicate_and_DefaultIfEmpty_projecting_root_collection_element_and_another_collection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Distinct_on_grouping_element(bool async) + { + return base.Skip_Take_Distinct_on_grouping_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_inside_collection_projection(bool async) + { + return base.Skip_Take_on_grouping_element_inside_collection_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_on_grouping_element_with_reference_include(bool async) + { + return base.Skip_Take_on_grouping_element_with_reference_include(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_Take_Select_collection_Skip_Take(bool async) + { + return base.Skip_Take_Select_collection_Skip_Take(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Take_Select_collection_Take(bool async) + { + return base.Take_Select_collection_Take(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsQueryFbTest.cs index 2187308b4..5b0edb499 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsQueryFbTest.cs @@ -15,13 +15,11 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using System; using System.Threading.Tasks; -using System.Linq; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; -using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.TestModels.ComplexNavigationsModel; -using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -557,12 +555,6 @@ public override Task GroupJoin_with_complex_subquery_with_joins_does_not_get_fla return base.GroupJoin_with_complex_subquery_with_joins_does_not_get_flattened3(isAsync); } - [GeneratedNameTooLongFact] - public override void Include18() - { - base.Include18(); - } - [GeneratedNameTooLongTheory] [MemberData(nameof(IsAsyncData))] public override Task Include18_1_1(bool isAsync) @@ -570,10 +562,11 @@ public override Task Include18_1_1(bool isAsync) return base.Include18_1_1(isAsync); } - [GeneratedNameTooLongFact] - public override void Include19() + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include19(bool isAsync) { - base.Include19(); + return base.Include19(isAsync); } [GeneratedNameTooLongTheory] @@ -697,10 +690,46 @@ public override Task Include_reference_with_groupby_in_subquery(bool async) [GeneratedNameTooLongTheory] [MemberData(nameof(IsAsyncData))] - public override Task Project_shadow_properties(bool async) + public override Task Project_shadow_properties1(bool async) + { + return base.Project_shadow_properties1(async); + } + + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties2(bool async) + { + return base.Project_shadow_properties2(async); + } + + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties3(bool async) + { + return base.Project_shadow_properties3(async); + } + + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties4(bool async) + { + return base.Project_shadow_properties4(async); + } + + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties9(bool async) + { + return base.Project_shadow_properties9(async); + } + + [GeneratedNameTooLongTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties10(bool async) { - return base.Project_shadow_properties(async); + return base.Project_shadow_properties10(async); } + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] public override Task SelectMany_with_outside_reference_to_joined_table_correctly_translated_to_apply(bool isAsync) @@ -721,4 +750,39 @@ public override Task Prune_does_not_throw_null_ref(bool async) { return base.Prune_does_not_throw_null_ref(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_with_subquery_on_inner(bool async) + { + return base.GroupJoin_with_subquery_on_inner(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_with_subquery_on_inner_and_no_DefaultIfEmpty(bool async) + { + return base.GroupJoin_with_subquery_on_inner_and_no_DefaultIfEmpty(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) + { + return base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_client_method_in_OrderBy(bool async) + { + return AssertTranslationFailed(() => base.GroupJoin_client_method_in_OrderBy(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_with_result_selector_returning_queryable_throws_validation_error(bool async) + { + return Assert.ThrowsAsync(() => base.Join_with_result_selector_returning_queryable_throws_validation_error(async)); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbFixture.cs similarity index 76% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbFixture.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbFixture.cs index d1f63ec7f..6639d6a7b 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbFixture.cs @@ -17,21 +17,19 @@ using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; -using FirebirdSql.EntityFrameworkCore.Firebird.Metadata; using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.TestModels.UpdatesModel; +using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; -namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests; +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class UpdatesFbFixture : UpdatesRelationalFixture +public class ComplexNavigationsSharedTypeQueryFbFixture : ComplexNavigationsSharedTypeQueryRelationalFixtureBase { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) { base.OnModelCreating(modelBuilder, context); - ModelHelpers.SetStringLengths(modelBuilder); - ModelHelpers.SetPrimaryKeyGeneration(modelBuilder, FbValueGenerationStrategy.IdentityColumn, x => x.ClrType == typeof(Person)); + ModelHelpers.SimpleTableNames(modelBuilder); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbTest.cs new file mode 100644 index 000000000..2d69e9631 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ComplexNavigationsSharedTypeQueryFbTest.cs @@ -0,0 +1,91 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ComplexNavigationsSharedTypeQueryFbTest : ComplexNavigationsSharedTypeQueryRelationalTestBase +{ + public ComplexNavigationsSharedTypeQueryFbTest(ComplexNavigationsSharedTypeQueryFbFixture fixture) + : base(fixture) + { } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_with_result_selector_returning_queryable_throws_validation_error(bool async) + { + return Assert.ThrowsAsync(() => base.Join_with_result_selector_returning_queryable_throws_validation_error(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_client_method_in_OrderBy(bool async) + { + return AssertTranslationFailed(() => base.GroupJoin_client_method_in_OrderBy(async)); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_with_subquery_on_inner(bool async) + { + return base.GroupJoin_with_subquery_on_inner(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_with_subquery_on_inner_and_no_DefaultIfEmpty(bool async) + { + return base.GroupJoin_with_subquery_on_inner_and_no_DefaultIfEmpty(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Let_let_contains_from_outer_let(bool async) + { + return base.Let_let_contains_from_outer_let(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(bool async) + { + return base.Nested_SelectMany_correlated_with_join_table_correctly_translated_to_apply(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Prune_does_not_throw_null_ref(bool async) + { + return base.Prune_does_not_throw_null_ref(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Project_shadow_properties10(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Project_shadow_properties10(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbFixture.cs new file mode 100644 index 000000000..2a3984d3a --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbFixture.cs @@ -0,0 +1,35 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class CompositeKeysQueryFbFixture : CompositeKeysQueryRelationalFixtureBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SimpleTableNames(modelBuilder); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbTest.cs new file mode 100644 index 000000000..c4b8eed66 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysQueryFbTest.cs @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class CompositeKeysQueryFbTest : CompositeKeysQueryRelationalTestBase +{ + public CompositeKeysQueryFbTest(CompositeKeysQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysSplitQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysSplitQueryFbTest.cs new file mode 100644 index 000000000..82d9dfbd6 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/CompositeKeysSplitQueryFbTest.cs @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class CompositeKeysSplitQueryFbTest : CompositeKeysSplitQueryRelationalTestBase +{ + public CompositeKeysSplitQueryFbTest(CompositeKeysQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/Ef6GroupByFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/Ef6GroupByFbTest.cs new file mode 100644 index 000000000..8735d6788 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/Ef6GroupByFbTest.cs @@ -0,0 +1,58 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class Ef6GroupByFbTest : Ef6GroupByTestBase +{ + public Ef6GroupByFbTest(Ef6GroupByFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Group_Join_from_LINQ_101(bool async) + { + return base.Group_Join_from_LINQ_101(async); + } + + [Theory(Skip = "Different math on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Average_Grouped_from_LINQ_101(bool async) + { + return base.Average_Grouped_from_LINQ_101(async); + } + + public class Ef6GroupByFbFixture : Ef6GroupByFixtureBase + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SetStringLengths(modelBuilder); + } + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/EntitySplittingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/EntitySplittingQueryFbTest.cs new file mode 100644 index 000000000..8c02f77e2 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/EntitySplittingQueryFbTest.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class EntitySplittingQueryFbTest : EntitySplittingQueryTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs index 36830eb32..f306be02a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/FromSqlQueryFbTest.cs @@ -95,11 +95,11 @@ public override async Task FromSql_used_twice_without_parameters(bool async) ? await query.AnyAsync() : query.Any(); - Assert.Equal( - RelationalStrings.QueryFromSqlInsideExists, - async - ? (await Assert.ThrowsAsync(() => query.AnyAsync())).Message - : Assert.Throws(() => query.Any()).Message); + var result2 = async + ? await query.AnyAsync() + : query.Any(); + + Assert.Equal(result1, result2); } [Theory] @@ -116,11 +116,11 @@ public override async Task FromSql_used_twice_with_parameters(bool async) ? await query.AnyAsync() : query.Any(); - Assert.Equal( - RelationalStrings.QueryFromSqlInsideExists, - async - ? (await Assert.ThrowsAsync(() => query.AnyAsync())).Message - : Assert.Throws(() => query.Any()).Message); + var result2 = async + ? await query.AnyAsync() + : query.Any(); + + Assert.Equal(result1, result2); } [Theory(Skip = "Provider does the casting.")] diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs index 113381677..3d832cce1 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/GearsOfWarQueryFbTest.cs @@ -159,6 +159,13 @@ public override Task Where_datetimeoffset_year_component(bool isAsync) return base.Where_datetimeoffset_year_component(isAsync); } + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffsetNow_minus_timespan(bool async) + { + return base.DateTimeOffsetNow_minus_timespan(async); + } + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] public override Task Correlated_collections_inner_subquery_predicate_references_outer_qsre(bool isAsync) @@ -376,18 +383,18 @@ public override Task Where_TimeOnly_subtract_TimeOnly(bool async) return base.Where_TimeOnly_subtract_TimeOnly(async); } - [Theory(Skip = "NETProvider#1008")] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Where_TimeOnly_IsBetween(bool async) + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) { - return base.Where_TimeOnly_IsBetween(async); + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); } - [Theory] + [Theory(Skip = "NETProvider#1008")] [MemberData(nameof(IsAsyncData))] - public override Task Where_TimeOnly_AddMinutes(bool async) + public override Task Where_TimeOnly_IsBetween(bool async) { - return base.Where_TimeOnly_AddMinutes(async); + return base.Where_TimeOnly_IsBetween(async); } [Theory(Skip = "NETProvider#1009")] diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyHeterogeneousQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyHeterogeneousQueryFbTest.cs new file mode 100644 index 000000000..910e239cf --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyHeterogeneousQueryFbTest.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ManyToManyHeterogeneousQueryFbTest : ManyToManyHeterogeneousQueryRelationalTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyNoTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyNoTrackingQueryFbTest.cs index 8016dfb56..bc451b955 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyNoTrackingQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyNoTrackingQueryFbTest.cs @@ -41,4 +41,11 @@ public override Task Skip_navigation_order_by_single_or_default(bool async) { return base.Skip_navigation_order_by_single_or_default(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbFixture.cs index 11db9b7bc..28750584c 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbFixture.cs @@ -15,7 +15,9 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -24,4 +26,10 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class ManyToManyQueryFbFixture : ManyToManyQueryRelationalFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.ShortenMM(modelBuilder); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbTest.cs index 38da8fc0a..d9a425e7f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ManyToManyQueryFbTest.cs @@ -42,4 +42,11 @@ public override Task Skip_navigation_order_by_single_or_default(bool async) { return base.Skip_navigation_order_by_single_or_default(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs new file mode 100644 index 000000000..fe50eb71c --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindAggregateOperatorsQueryFbTest.cs @@ -0,0 +1,75 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindAggregateOperatorsQueryFbTest : NorthwindAggregateOperatorsQueryRelationalTestBase> +{ + public NorthwindAggregateOperatorsQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Multiple_collection_navigation_with_FirstOrDefault_chained(bool async) + { + return base.Multiple_collection_navigation_with_FirstOrDefault_chained(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Contains_with_local_anonymous_type_array_closure(bool async) + { + return AssertTranslationFailed(() => base.Contains_with_local_anonymous_type_array_closure(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Contains_with_local_tuple_array_closure(bool async) + { + return AssertTranslationFailed(() => base.Contains_with_local_tuple_array_closure(async)); + } + + [Theory(Skip = "Different math on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Average_over_max_subquery_is_client_eval(bool async) + { + return base.Average_over_max_subquery_is_client_eval(async); + } + + [Theory(Skip = "Different math on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Average_over_nested_subquery_is_client_eval(bool async) + { + return base.Average_over_nested_subquery_is_client_eval(async); + } + + [Theory(Skip = "Different math on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Sum_with_division_on_decimal(bool async) + { + return base.Sum_with_division_on_decimal(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryFbTest.cs new file mode 100644 index 000000000..b78628c3e --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindEFPropertyIncludeQueryFbTest.cs @@ -0,0 +1,146 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindEFPropertyIncludeQueryFbTest : NorthwindEFPropertyIncludeQueryTestBase> +{ + public NorthwindEFPropertyIncludeQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_empty_list_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_does_not_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_empty_list_does_not_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_list_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_duplicate_collection_result_operator(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator2(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_duplicate_collection_result_operator2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_multiple_ordering(bool async) + { + return base.Filtered_include_with_multiple_ordering(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter(bool async) + { + return base.Include_collection_with_outer_apply_with_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + return base.Include_collection_with_outer_apply_with_filter_non_equality(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_cross_apply_with_filter(bool async) + { + return base.Include_collection_with_cross_apply_with_filter(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_last_no_orderby(bool async) + { + return Assert.ThrowsAsync(() => base.Include_collection_with_last_no_orderby(async)); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Repro9735(bool async) + { + return base.Repro9735(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + return base.SelectMany_Include_reference_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + return base.SelectMany_Include_collection_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_Include_reference_GroupBy_Select(bool async) + { + return base.Join_Include_reference_GroupBy_Select(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs new file mode 100644 index 000000000..d3ef9d563 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindFunctionsQueryFbTest.cs @@ -0,0 +1,285 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindFunctionsQueryFbTest : NorthwindFunctionsQueryRelationalTestBase> +{ + public NorthwindFunctionsQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToBoolean(bool async) + { + return base.Convert_ToBoolean(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToByte(bool async) + { + return base.Convert_ToByte(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToDecimal(bool async) + { + return base.Convert_ToDecimal(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToDouble(bool async) + { + return base.Convert_ToDouble(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToInt16(bool async) + { + return base.Convert_ToInt16(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToInt32(bool async) + { + return base.Convert_ToInt32(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToInt64(bool async) + { + return base.Convert_ToInt64(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Convert_ToString(bool async) + { + return base.Convert_ToString(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Trim_with_char_array_argument_in_predicate(bool async) + { + return base.Trim_with_char_array_argument_in_predicate(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task TrimEnd_with_char_array_argument_in_predicate(bool async) + { + return base.TrimEnd_with_char_array_argument_in_predicate(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task TrimStart_with_char_array_argument_in_predicate(bool async) + { + return base.TrimStart_with_char_array_argument_in_predicate(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Regex_IsMatch_MethodCall(bool async) + { + return base.Regex_IsMatch_MethodCall(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Regex_IsMatch_MethodCall_constant_input(bool async) + { + return base.Regex_IsMatch_MethodCall_constant_input(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_abs1(bool async) + { + return base.Where_mathf_abs1(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_acos(bool async) + { + return base.Where_mathf_acos(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_asin(bool async) + { + return base.Where_mathf_asin(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_atan(bool async) + { + return base.Where_mathf_atan(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_atan2(bool async) + { + return base.Where_mathf_atan2(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_ceiling1(bool async) + { + return base.Where_mathf_ceiling1(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_cos(bool async) + { + return base.Where_mathf_cos(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_exp(bool async) + { + return base.Where_mathf_exp(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_floor(bool async) + { + return base.Where_mathf_floor(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_log(bool async) + { + return base.Where_mathf_log(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_log_new_base(bool async) + { + return base.Where_mathf_log_new_base(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_log10(bool async) + { + return base.Where_mathf_log10(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_power(bool async) + { + return base.Where_mathf_power(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_round2(bool async) + { + return base.Where_mathf_round2(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_sign(bool async) + { + return base.Where_mathf_sign(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_sin(bool async) + { + return base.Where_mathf_sin(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_sqrt(bool async) + { + return base.Where_mathf_sqrt(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_square(bool async) + { + return base.Where_mathf_square(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_tan(bool async) + { + return base.Where_mathf_tan(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_mathf_truncate(bool async) + { + return base.Where_mathf_truncate(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Datetime_subtraction_TotalDays(bool async) + { + return base.Datetime_subtraction_TotalDays(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task String_FirstOrDefault_MethodCall(bool async) + { + return base.String_FirstOrDefault_MethodCall(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task String_LastOrDefault_MethodCall(bool async) + { + return base.String_LastOrDefault_MethodCall(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindGroupByQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindGroupByQueryFbTest.cs index 9f7926b42..dbbdc0a75 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindGroupByQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindGroupByQueryFbTest.cs @@ -89,29 +89,26 @@ public override Task Complex_query_with_groupBy_in_subquery3(bool async) [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Select_nested_collection_with_groupby(bool async) + public override Task Complex_query_with_groupBy_in_subquery4(bool async) { - return base.Select_nested_collection_with_groupby(async); + return base.Complex_query_with_groupBy_in_subquery4(async); } [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Select_uncorrelated_collection_with_groupby_when_outer_is_distinct(bool async) + public override Task Select_nested_collection_with_groupby(bool async) { - return base.Select_uncorrelated_collection_with_groupby_when_outer_is_distinct(async); + return base.Select_nested_collection_with_groupby(async); } - [Theory] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override async Task Complex_query_with_groupBy_in_subquery4(bool async) + public override Task Select_uncorrelated_collection_with_groupby_when_outer_is_distinct(bool async) { - var message = (await Assert.ThrowsAsync( - () => base.Complex_query_with_groupBy_in_subquery4(async))).Message; - - Assert.Equal(RelationalStrings.InsufficientInformationToIdentifyElementOfCollectionJoin, message); + return base.Select_uncorrelated_collection_with_groupby_when_outer_is_distinct(async); } - [Theory] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] public override async Task Select_correlated_collection_after_GroupBy_aggregate_when_identifier_changes_to_complex(bool async) { diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryFbTest.cs new file mode 100644 index 000000000..1f719566f --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeNoTrackingQueryFbTest.cs @@ -0,0 +1,158 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using System.Threading.Tasks; +using System; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindIncludeNoTrackingQueryFbTest : NorthwindIncludeNoTrackingQueryTestBase> +{ + public NorthwindIncludeNoTrackingQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_multiple_ordering(bool async) + { + return base.Filtered_include_with_multiple_ordering(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter(bool async) + { + return base.Include_collection_with_outer_apply_with_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + return base.Include_collection_with_outer_apply_with_filter_non_equality(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_cross_apply_with_filter(bool async) + { + return base.Include_collection_with_cross_apply_with_filter(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_last_no_orderby(bool async) + { + return Assert.ThrowsAsync(() => base.Include_collection_with_last_no_orderby(async)); + } + + [Theory(Skip = "Different ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_list_contains(bool async) + { + return base.Include_collection_OrderBy_list_contains(async); + } + + [Theory(Skip = "Different ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_multiple_conditional_order_by(bool async) + { + return base.Include_collection_with_multiple_conditional_order_by(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator2(bool async) + { + return base.Include_duplicate_collection_result_operator2(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_take_no_order_by(bool async) + { + return base.Include_collection_take_no_order_by(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_skip_no_order_by(bool async) + { + return base.Include_collection_skip_no_order_by(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_skip_take_no_order_by(bool async) + { + return base.Include_collection_skip_take_no_order_by(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator(bool async) + { + return base.Include_duplicate_collection_result_operator(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Repro9735(bool async) + { + return base.Repro9735(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_contains(bool async) + { + return base.Include_collection_OrderBy_empty_list_contains(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_does_not_contains(bool async) + { + return base.Include_collection_OrderBy_empty_list_does_not_contains(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + return base.SelectMany_Include_reference_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + return base.SelectMany_Include_collection_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_Include_reference_GroupBy_Select(bool async) + { + return base.Join_Include_reference_GroupBy_Select(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeQueryFbTest.cs index 3437d9bb5..40c659ef4 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindIncludeQueryFbTest.cs @@ -121,6 +121,20 @@ public override Task Repro9735(bool async) return base.Repro9735(async); } + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_contains(bool async) + { + return base.Include_collection_OrderBy_empty_list_contains(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_does_not_contains(bool async) + { + return base.Include_collection_OrderBy_empty_list_does_not_contains(async); + } + [LongExecutionTheory] [MemberData(nameof(IsAsyncData))] public override Task SelectMany_Include_reference_GroupBy_Select(bool async) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs new file mode 100644 index 000000000..49609b886 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindJoinQueryFbTest.cs @@ -0,0 +1,117 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindJoinQueryFbTest : NorthwindJoinQueryRelationalTestBase> +{ + public NorthwindJoinQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_as_final_operator(bool async) + { + return base.GroupJoin_as_final_operator(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_SelectMany_subquery_with_filter_orderby(bool async) + { + return base.GroupJoin_SelectMany_subquery_with_filter_orderby(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupJoin_SelectMany_subquery_with_filter_orderby_and_DefaultIfEmpty(bool async) + { + return base.GroupJoin_SelectMany_subquery_with_filter_orderby_and_DefaultIfEmpty(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_client_eval(bool async) + { + return base.SelectMany_with_client_eval(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_client_eval_with_collection_shaper(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_client_eval_with_collection_shaper_ignored(bool async) + { + return base.SelectMany_with_client_eval_with_collection_shaper_ignored(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_selecting_outer_element(bool async) + { + return base.SelectMany_with_selecting_outer_element(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_selecting_outer_entity(bool async) + { + return base.SelectMany_with_selecting_outer_entity(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_selecting_outer_entity_column_and_inner_column(bool async) + { + return base.SelectMany_with_selecting_outer_entity_column_and_inner_column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Take_in_collection_projection_with_FirstOrDefault_on_top_level(bool async) + { + return base.Take_in_collection_projection_with_FirstOrDefault_on_top_level(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Unflattened_GroupJoin_composed(bool async) + { + return base.Unflattened_GroupJoin_composed(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Unflattened_GroupJoin_composed_2(bool async) + { + return base.Unflattened_GroupJoin_composed_2(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindKeylessEntitiesQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindKeylessEntitiesQueryFbTest.cs new file mode 100644 index 000000000..cae3409d5 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindKeylessEntitiesQueryFbTest.cs @@ -0,0 +1,65 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; +using Xunit.Sdk; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindKeylessEntitiesQueryFbTest : NorthwindKeylessEntitiesQueryRelationalTestBase> +{ + public NorthwindKeylessEntitiesQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task KeylessEntity_by_database_view(bool async) + { + return base.KeylessEntity_by_database_view(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Entity_mapped_to_view_on_right_side_of_join(bool async) + { + return base.Entity_mapped_to_view_on_right_side_of_join(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task KeylessEntity_with_nav_defining_query(bool async) + { + Assert.Equal( + "0", + (await Assert.ThrowsAsync( + () => base.KeylessEntity_with_nav_defining_query(async))).Actual); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Count_over_keyless_entity_with_pushdown_empty_projection(bool async) + { + return base.Count_over_keyless_entity_with_pushdown_empty_projection(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs new file mode 100644 index 000000000..b2fcee996 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindMiscellaneousQueryFbTest.cs @@ -0,0 +1,136 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindMiscellaneousQueryFbTest : NorthwindMiscellaneousQueryRelationalTestBase> +{ + public NorthwindMiscellaneousQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Select_DTO_constructor_distinct_with_collection_projection_translated_to_server_with_binding_after_client_eval(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Select_DTO_constructor_distinct_with_collection_projection_translated_to_server_with_binding_after_client_eval(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Client_code_unknown_method(bool async) + { + await AssertTranslationFailed(() => base.Client_code_unknown_method(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Client_code_using_instance_in_anonymous_type(bool async) + { + await Assert.ThrowsAsync(() => base.Client_code_using_instance_in_anonymous_type(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Client_code_using_instance_in_static_method(bool async) + { + await Assert.ThrowsAsync(() => base.Client_code_using_instance_in_static_method(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Client_code_using_instance_method_throws(bool async) + { + await Assert.ThrowsAsync(() => base.Client_code_using_instance_method_throws(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Entity_equality_through_subquery_composite_key(bool async) + { + await Assert.ThrowsAsync(() => base.Entity_equality_through_subquery_composite_key(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Max_on_empty_sequence_throws(bool async) + { + await Assert.ThrowsAsync(() => base.Max_on_empty_sequence_throws(async)); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(bool async) + { + return base.Complex_nested_query_doesnt_try_binding_to_grandparent_when_parent_returns_complex_result(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_distinct_without_default_identifiers_projecting_columns(bool async) + { + return base.Correlated_collection_with_distinct_without_default_identifiers_projecting_columns(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_distinct_without_default_identifiers_projecting_columns_with_navigation(bool async) + { + return base.Correlated_collection_with_distinct_without_default_identifiers_projecting_columns_with_navigation(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DefaultIfEmpty_in_subquery_nested_filter_order_comparison(bool async) + { + return base.DefaultIfEmpty_in_subquery_nested_filter_order_comparison(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Select_correlated_subquery_ordered(bool async) + { + return base.Select_correlated_subquery_ordered(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Select_subquery_recursive_trivial(bool async) + { + return base.Select_subquery_recursive_trivial(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_correlated_subquery_hard(bool async) + { + return base.SelectMany_correlated_subquery_hard(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs index 92c68e834..5219a5cac 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindQueryFbFixture.cs @@ -16,8 +16,10 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using System; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestModels.Northwind; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSelectQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSelectQueryFbTest.cs index b65932022..ccfb89ed9 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSelectQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSelectQueryFbTest.cs @@ -177,4 +177,53 @@ public override Task Take_on_top_level_and_on_collection_projection_with_outer_a { return base.Take_on_top_level_and_on_collection_projection_with_outer_apply(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_after_groupby_with_complex_projection_not_containing_original_identifier(bool async) + { + return base.Correlated_collection_after_groupby_with_complex_projection_not_containing_original_identifier(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Reverse_in_projection_subquery(bool async) + { + return base.Reverse_in_projection_subquery(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Reverse_in_projection_subquery_single_result(bool async) + { + return base.Reverse_in_projection_subquery_single_result(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Reverse_in_SelectMany_with_Take(bool async) + { + return base.Reverse_in_SelectMany_with_Take(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(bool async) + { + Assert.Equal( + RelationalStrings.InsufficientInformationToIdentifyElementOfCollectionJoin, + (await Assert.ThrowsAsync( + () => base.Correlated_collection_after_distinct_with_complex_projection_not_containing_original_identifier(async))) + .Message); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_with_collection_being_correlated_subquery_which_references_non_mapped_properties_from_inner_and_outer_entity(bool async) + { + return AssertUnableToTranslateEFProperty( + () => base + .SelectMany_with_collection_being_correlated_subquery_which_references_non_mapped_properties_from_inner_and_outer_entity( + async)); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSetOperationsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSetOperationsQueryFbTest.cs new file mode 100644 index 000000000..ecf161e9f --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSetOperationsQueryFbTest.cs @@ -0,0 +1,111 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindSetOperationsQueryFbTest : NorthwindSetOperationsQueryRelationalTestBase> +{ + public NorthwindSetOperationsQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override bool CanExecuteQueryString => false; + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_Select_scalar(bool async) + { + return base.Union_Select_scalar(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Select_Except_reference_projection(bool async) + { + return base.Select_Except_reference_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Except(bool async) + { + return base.Except(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Except_nested(bool async) + { + return base.Except_nested(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Except_non_entity(bool async) + { + return base.Except_non_entity(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Except_simple_followed_by_projecting_constant(bool async) + { + return base.Except_simple_followed_by_projecting_constant(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Intersect(bool async) + { + return base.Intersect(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Intersect_nested(bool async) + { + return base.Intersect_nested(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Intersect_non_entity(bool async) + { + return base.Intersect_non_entity(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Union_Intersect(bool async) + { + return base.Union_Intersect(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Client_eval_Union_FirstOrDefault(bool async) + { + return Assert.ThrowsAsync(() => base.Client_eval_Union_FirstOrDefault(async)); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryFbTest.cs new file mode 100644 index 000000000..e42c78daf --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeNoTrackingQueryFbTest.cs @@ -0,0 +1,105 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindSplitIncludeNoTrackingQueryFbTest : NorthwindSplitIncludeNoTrackingQueryTestBase> +{ + public NorthwindSplitIncludeNoTrackingQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Repro9735(bool async) + { + return base.Repro9735(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_SelectMany_GroupBy_Select(bool async) + { + return base.Include_collection_SelectMany_GroupBy_Select(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_list_contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_multiple_ordering(bool async) + { + return base.Filtered_include_with_multiple_ordering(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_cross_apply_with_filter(bool async) + { + return base.Include_collection_with_cross_apply_with_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + return base.Include_collection_with_outer_apply_with_filter_non_equality(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter(bool async) + { + return base.Include_collection_with_outer_apply_with_filter(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_Include_reference_GroupBy_Select(bool async) + { + return base.Join_Include_reference_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + return base.SelectMany_Include_collection_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + return base.SelectMany_Include_reference_GroupBy_Select(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeQueryFbTest.cs new file mode 100644 index 000000000..18f4958d0 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSplitIncludeQueryFbTest.cs @@ -0,0 +1,105 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindSplitIncludeQueryFbTest : NorthwindSplitIncludeQueryTestBase> +{ + public NorthwindSplitIncludeQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Repro9735(bool async) + { + return base.Repro9735(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_SelectMany_GroupBy_Select(bool async) + { + return base.Include_collection_SelectMany_GroupBy_Select(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_list_contains(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_with_multiple_ordering(bool async) + { + return base.Filtered_include_with_multiple_ordering(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_cross_apply_with_filter(bool async) + { + return base.Include_collection_with_cross_apply_with_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + return base.Include_collection_with_outer_apply_with_filter_non_equality(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter(bool async) + { + return base.Include_collection_with_outer_apply_with_filter(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_Include_reference_GroupBy_Select(bool async) + { + return base.Join_Include_reference_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + return base.SelectMany_Include_collection_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + return base.SelectMany_Include_reference_GroupBy_Select(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSqlQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSqlQueryFbTest.cs new file mode 100644 index 000000000..be20a2043 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindSqlQueryFbTest.cs @@ -0,0 +1,33 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Data.Common; +using FirebirdSql.Data.FirebirdClient; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindSqlQueryFbTest : NorthwindSqlQueryTestBase> +{ + public NorthwindSqlQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + protected override DbParameter CreateDbParameter(string name, object value) + => new FbParameter { ParameterName = name, Value = value }; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindStringIncludeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindStringIncludeQueryFbTest.cs new file mode 100644 index 000000000..aa31a194c --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindStringIncludeQueryFbTest.cs @@ -0,0 +1,144 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Linq; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class NorthwindStringIncludeQueryFbTest : NorthwindStringIncludeQueryTestBase> +{ + public NorthwindStringIncludeQueryFbTest(NorthwindQueryFbFixture fixture) + : base(fixture) + { } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Repro9735(bool async) + { + return base.Repro9735(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_empty_list_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_empty_list_does_not_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_empty_list_does_not_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_OrderBy_list_contains(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_collection_OrderBy_list_contains(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_duplicate_collection_result_operator(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_duplicate_collection_result_operator2(bool async) + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return Task.CompletedTask; + return base.Include_duplicate_collection_result_operator2(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_cross_apply_with_filter(bool async) + { + return base.Include_collection_with_cross_apply_with_filter(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter_non_equality(bool async) + { + return base.Include_collection_with_outer_apply_with_filter_non_equality(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Include_collection_with_outer_apply_with_filter(bool async) + { + return base.Include_collection_with_outer_apply_with_filter(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override async Task Include_collection_with_last_no_orderby(bool async) + { + Assert.Equal( + RelationalStrings.LastUsedWithoutOrderBy(nameof(Enumerable.Last)), + (await Assert.ThrowsAsync( + () => base.Include_collection_with_last_no_orderby(async))).Message); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Join_Include_reference_GroupBy_Select(bool async) + { + return base.Join_Include_reference_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_collection_GroupBy_Select(bool async) + { + return base.SelectMany_Include_collection_GroupBy_Select(async); + } + + [LongExecutionTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_Include_reference_GroupBy_Select(bool async) + { + return base.SelectMany_Include_reference_GroupBy_Select(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindWhereQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindWhereQueryFbTest.cs index 25ec259e2..9b30b4475 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindWhereQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/NorthwindWhereQueryFbTest.cs @@ -85,4 +85,74 @@ public override Task Where_datetimeoffset_utcnow(bool async) { return base.Where_datetimeoffset_utcnow(async); } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_bitwise_xor(bool async) + { + return AssertTranslationFailed(() => base.Where_bitwise_xor(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_constructed_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_constructed_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_constructed_multi_value_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_constructed_multi_value_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_constructed_multi_value_not_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_constructed_multi_value_not_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_constructed_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_constructed_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_constructed_multi_value_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_constructed_multi_value_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_constructed_multi_value_not_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_constructed_multi_value_not_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_create_constructed_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_create_constructed_multi_value_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_multi_value_equal(async)); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_compare_tuple_create_constructed_multi_value_not_equal(bool async) + { + return AssertTranslationFailed(() => base.Where_compare_tuple_create_constructed_multi_value_not_equal(async)); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedEntityQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedEntityQueryFbTest.cs new file mode 100644 index 000000000..f7c61b159 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedEntityQueryFbTest.cs @@ -0,0 +1,37 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class OwnedEntityQueryFbTest : OwnedEntityQueryRelationalTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Multiple_owned_reference_mapped_to_own_table_containing_owned_collection_in_split_query(bool async) + { + return base.Multiple_owned_reference_mapped_to_own_table_containing_owned_collection_in_split_query(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedQueryFbTest.cs index ff1e0dcbf..834e3a234 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/OwnedQueryFbTest.cs @@ -388,6 +388,41 @@ public override Task Owned_entity_without_owner_does_not_throw_for_identity_reso return base.Owned_entity_without_owner_does_not_throw_for_identity_resolution(async, useAsTracking); } + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Can_query_owner_with_different_owned_types_having_same_property_name_in_hierarchy(bool async) + { + return base.Can_query_owner_with_different_owned_types_having_same_property_name_in_hierarchy(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task GroupBy_aggregate_on_owned_navigation_in_aggregate_selector(bool async) + { + return base.GroupBy_aggregate_on_owned_navigation_in_aggregate_selector(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Left_join_on_entity_with_owned_navigations(bool async) + { + return base.Left_join_on_entity_with_owned_navigations(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Left_join_on_entity_with_owned_navigations_complex(bool async) + { + return base.Left_join_on_entity_with_owned_navigations_complex(async); + } + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Simple_query_entity_with_owned_collection(bool async) + { + return base.Simple_query_entity_with_owned_collection(async); + } + public class OwnedQueryFbFixture : RelationalOwnedQueryFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs index a3a0d7511..f06645473 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryFilterFuncletizationFbTest.cs @@ -34,9 +34,31 @@ public QueryFilterFuncletizationFbTest(QueryFilterFuncletizationFbFixture fixtur : base(fixture) { } + [Fact] + public override void DbContext_complex_expression_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_complex_expression_is_parameterized(); + } + + [Fact] + public override void DbContext_field_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_field_is_parameterized(); + } + [Fact] public override void DbContext_list_is_parameterized() { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + using var context = CreateContext(); // Default value of TenantIds is null InExpression over null values throws Assert.Throws(() => context.Set().ToList()); @@ -54,6 +76,222 @@ public override void DbContext_list_is_parameterized() Assert.Equal(2, query.Count); } + [Fact] + public override void DbContext_method_call_chain_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_method_call_chain_is_parameterized(); + } + + [Fact] + public override void DbContext_method_call_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_method_call_is_parameterized(); + } + + [Fact] + public override void DbContext_property_based_filter_does_not_short_circuit() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_property_based_filter_does_not_short_circuit(); + } + + [Fact] + public override void DbContext_property_chain_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_property_chain_is_parameterized(); + } + + [Fact] + public override void DbContext_property_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_property_is_parameterized(); + } + + [Fact] + public override void DbContext_property_method_call_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_property_method_call_is_parameterized(); + } + + [Fact] + public override void DbContext_property_parameter_does_not_clash_with_closure_parameter_name() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.DbContext_property_parameter_does_not_clash_with_closure_parameter_name(); + } + + [Fact] + public override void EntityTypeConfiguration_DbContext_field_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.EntityTypeConfiguration_DbContext_field_is_parameterized(); + } + + [Fact] + public override void EntityTypeConfiguration_DbContext_method_call_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.EntityTypeConfiguration_DbContext_method_call_is_parameterized(); + } + + [Fact] + public override void EntityTypeConfiguration_DbContext_property_chain_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.EntityTypeConfiguration_DbContext_property_chain_is_parameterized(); + } + + [Fact] + public override void EntityTypeConfiguration_DbContext_property_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.EntityTypeConfiguration_DbContext_property_is_parameterized(); + } + + [Fact] + public override void Extension_method_DbContext_field_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Extension_method_DbContext_field_is_parameterized(); + } + + [Fact] + public override void Extension_method_DbContext_property_chain_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Extension_method_DbContext_property_chain_is_parameterized(); + } + + [Fact] + public override void Local_method_DbContext_field_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Local_method_DbContext_field_is_parameterized(); + } + + [Fact] + public override void Local_static_method_DbContext_property_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Local_static_method_DbContext_property_is_parameterized(); + } + + [Fact] + public override void Local_variable_from_OnModelCreating_can_throw_exception() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Local_variable_from_OnModelCreating_can_throw_exception(); + } + + [Fact] + public override void Local_variable_from_OnModelCreating_is_inlined() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Local_variable_from_OnModelCreating_is_inlined(); + } + + [Fact] + public override void Method_parameter_is_inlined() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Method_parameter_is_inlined(); + } + + [Fact] + public override void Remote_method_DbContext_property_method_call_is_parameterized() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Remote_method_DbContext_property_method_call_is_parameterized(); + } + + [Fact] + public override void Static_member_from_dbContext_is_inlined() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Static_member_from_dbContext_is_inlined(); + } + + [Fact] + public override void Static_member_from_non_dbContext_is_inlined() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Static_member_from_non_dbContext_is_inlined(); + } + + [Fact] + public override void Using_Context_set_method_in_filter_works() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Using_Context_set_method_in_filter_works(); + } + + [Fact] + public override void Using_DbSet_in_filter_works() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Using_DbSet_in_filter_works(); + } + + [Fact] + public override void Using_multiple_context_in_filter_parametrize_only_current_context() + { + var fbTestStore = (FbTestStore)Fixture.TestStore; + if (fbTestStore.ServerLessThan4()) + return; + base.Using_multiple_context_in_filter_parametrize_only_current_context(); + } + public class QueryFilterFuncletizationFbFixture : QueryFilterFuncletizationRelationalFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbTest.cs index 8faaf0b99..1a88ccebe 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbTest.cs @@ -16,12 +16,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class QueryNoClientEvalFbTest : QueryNoClientEvalTestBase +public class QueryNoClientEvalFbTest : QueryNoClientEvalTestBase> { - public QueryNoClientEvalFbTest(QueryNoClientEvalFbFixture fixture) + public QueryNoClientEvalFbTest(NorthwindQueryFbFixture fixture) : base(fixture) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SharedTypeQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SharedTypeQueryFbTest.cs new file mode 100644 index 000000000..4df2ba1bb --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SharedTypeQueryFbTest.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class SharedTypeQueryFbTest : SharedTypeQueryRelationalTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SimpleQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SimpleQueryFbTest.cs new file mode 100644 index 000000000..06c511f52 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/SimpleQueryFbTest.cs @@ -0,0 +1,81 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class SimpleQueryFbTest : SimpleQueryRelationalTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + [DoesNotHaveTheDataTheory] + [MemberData(nameof(IsAsyncData))] + public override Task StoreType_for_UDF_used(bool async) + { + return base.StoreType_for_UDF_used(async); + } + + [Theory(Skip = "Not interesting for Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Multiple_different_entity_type_from_different_namespaces(bool async) + { + return base.Multiple_different_entity_type_from_different_namespaces(async); + } + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Multiple_nested_reference_navigations(bool async) + { + return base.Multiple_nested_reference_navigations(async); + } + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Comparing_byte_column_to_enum_in_vb_creating_double_cast(bool async) + { + return base.Comparing_byte_column_to_enum_in_vb_creating_double_cast(async); + } + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Comparing_enum_casted_to_byte_with_int_constant(bool async) + { + return base.Comparing_enum_casted_to_byte_with_int_constant(async); + } + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Comparing_enum_casted_to_byte_with_int_parameter(bool async) + { + return base.Comparing_enum_casted_to_byte_with_int_parameter(async); + } + + [HasDataInTheSameTransactionAsDDLTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Null_check_removal_in_ternary_maintain_appropriate_cast(bool async) + { + return base.Null_check_removal_in_ternary_maintain_appropriate_cast(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs similarity index 83% rename from src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbFixture.cs rename to src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs index 36f348e0a..c3634770c 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/QueryNoClientEvalFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbFixture.cs @@ -15,9 +15,9 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using Microsoft.EntityFrameworkCore.TestUtilities; - namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class QueryNoClientEvalFbFixture : NorthwindQueryFbFixture -{ } +public class TPCFiltersInheritanceQueryFbFixture : TPCInheritanceQueryFbFixture +{ + protected override bool EnableFilters => true; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbTest.cs new file mode 100644 index 000000000..395a61b57 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCFiltersInheritanceQueryFbTest.cs @@ -0,0 +1,28 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCFiltersInheritanceQueryFbTest : TPCFiltersInheritanceQueryTestBase +{ + public TPCFiltersInheritanceQueryFbTest(TPCFiltersInheritanceQueryFbFixture fixture) + : base(fixture) + { } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbFixture.cs new file mode 100644 index 000000000..fe4c60fbc --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbFixture.cs @@ -0,0 +1,46 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCGearsOfWarQueryFbFixture : TPCGearsOfWarQueryRelationalFixture +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SetStringLengths(modelBuilder); + + modelBuilder.Entity().Property(g => g.Location).HasColumnType("varchar(100)"); + + // No support yet for DateOnly/TimeOnly (#24507) + modelBuilder.Entity( + b => + { + b.Ignore(m => m.Date); + b.Ignore(m => m.Time); + }); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs new file mode 100644 index 000000000..d93eab640 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCGearsOfWarQueryFbTest.cs @@ -0,0 +1,448 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.GearsOfWarModel; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCGearsOfWarQueryFbTest : TPCGearsOfWarQueryRelationalTestBase +{ + public TPCGearsOfWarQueryFbTest(TPCGearsOfWarQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Array_access_on_byte_array(bool async) + { + return base.Array_access_on_byte_array(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_after_distinct_3_levels(bool async) + { + return base.Correlated_collection_after_distinct_3_levels(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_via_SelectMany_with_Distinct_missing_indentifying_columns_in_projection(bool async) + { + return base.Correlated_collection_via_SelectMany_with_Distinct_missing_indentifying_columns_in_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_distinct_not_projecting_identifier_column(bool async) + { + return base.Correlated_collection_with_distinct_not_projecting_identifier_column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_distinct_projecting_identifier_column(bool async) + { + return base.Correlated_collection_with_distinct_projecting_identifier_column(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_not_projecting_identifier_column_but_only_grouping_key_in_final_projection(bool async) + { + return base.Correlated_collection_with_groupby_not_projecting_identifier_column_but_only_grouping_key_in_final_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) + { + return base.Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection_multiple_grouping_keys(bool async) + { + return base.Correlated_collection_with_groupby_not_projecting_identifier_column_with_group_aggregate_in_final_projection_multiple_grouping_keys(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) + { + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collection_with_inner_collection_references_element_two_levels_up(bool async) + { + return base.Correlated_collection_with_inner_collection_references_element_two_levels_up(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collections_inner_subquery_predicate_references_outer_qsre(bool async) + { + return base.Correlated_collections_inner_subquery_predicate_references_outer_qsre(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collections_inner_subquery_selector_references_outer_qsre(bool async) + { + return base.Correlated_collections_inner_subquery_selector_references_outer_qsre(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(bool async) + { + return base.Correlated_collections_nested_inner_subquery_references_outer_qsre_one_level_up(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(bool async) + { + return base.Correlated_collections_nested_inner_subquery_references_outer_qsre_two_levels_up(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Correlated_collections_with_Distinct(bool async) + { + return base.Correlated_collections_with_Distinct(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) + { + return base.DateTimeOffset_Contains_Less_than_Greater_than(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffset_Date_returns_datetime(bool async) + { + return base.DateTimeOffset_Date_returns_datetime(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffsetNow_minus_timespan(bool async) + { + return base.DateTimeOffsetNow_minus_timespan(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task First_on_byte_array(bool async) + { + return base.First_on_byte_array(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Outer_parameter_in_group_join_with_DefaultIfEmpty(bool async) + { + return base.Outer_parameter_in_group_join_with_DefaultIfEmpty(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Outer_parameter_in_join_key(bool async) + { + return base.Outer_parameter_in_join_key(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Outer_parameter_in_join_key_inner_and_outer(bool async) + { + return base.Outer_parameter_in_join_key_inner_and_outer(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(bool async) + { + return base.SelectMany_predicate_with_non_equality_comparison_with_Take_doesnt_convert_to_join(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion(bool async) + { + return base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion_negated(bool async) + { + return base.Subquery_projecting_non_nullable_scalar_contains_non_nullable_value_doesnt_need_null_expansion_negated(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion(bool async) + { + return base.Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion_negated(bool async) + { + return base.Subquery_projecting_nullable_scalar_contains_nullable_value_needs_null_expansion_negated(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_AddDays(bool async) + { + return base.Where_DateOnly_AddDays(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_AddMonths(bool async) + { + return base.Where_DateOnly_AddMonths(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_AddYears(bool async) + { + return base.Where_DateOnly_AddYears(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_Day(bool async) + { + return base.Where_DateOnly_Day(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_DayOfWeek(bool async) + { + return base.Where_DateOnly_DayOfWeek(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_DayOfYear(bool async) + { + return base.Where_DateOnly_DayOfYear(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_Month(bool async) + { + return base.Where_DateOnly_Month(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_DateOnly_Year(bool async) + { + return base.Where_DateOnly_Year(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_date_component(bool async) + { + return base.Where_datetimeoffset_date_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_day_component(bool async) + { + return base.Where_datetimeoffset_day_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_dayofyear_component(bool async) + { + return base.Where_datetimeoffset_dayofyear_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_hour_component(bool async) + { + return base.Where_datetimeoffset_hour_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_millisecond_component(bool async) + { + return base.Where_datetimeoffset_millisecond_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_minute_component(bool async) + { + return base.Where_datetimeoffset_minute_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_month_component(bool async) + { + return base.Where_datetimeoffset_month_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_now(bool async) + { + return base.Where_datetimeoffset_now(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_second_component(bool async) + { + return base.Where_datetimeoffset_second_component(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_utcnow(bool async) + { + return base.Where_datetimeoffset_utcnow(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_datetimeoffset_year_component(bool async) + { + return base.Where_datetimeoffset_year_component(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Add_TimeSpan(bool async) + { + return base.Where_TimeOnly_Add_TimeSpan(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_AddHours(bool async) + { + return base.Where_TimeOnly_AddHours(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_AddMinutes(bool async) + { + return base.Where_TimeOnly_AddMinutes(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Hour(bool async) + { + return base.Where_TimeOnly_Hour(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_IsBetween(bool async) + { + return base.Where_TimeOnly_IsBetween(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Millisecond(bool async) + { + return base.Where_TimeOnly_Millisecond(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Minute(bool async) + { + return base.Where_TimeOnly_Minute(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Second(bool async) + { + return base.Where_TimeOnly_Second(async); + } + + [NotSupportedByProviderTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_subtract_TimeOnly(bool async) + { + return base.Where_TimeOnly_subtract_TimeOnly(async); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_nullable(bool async) + { + return AssertQuery(async, (ISetSource ss) => from lh in ss.Set() + select ((object)lh.Eradicated).ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_nullable"); + } + + [Theory] + [MemberData(nameof(IsAsyncData))] + public override Task ToString_boolean_property_non_nullable(bool async) + { + return AssertQuery(async, (ISetSource ss) => from w in ss.Set() + select w.IsAutomatic.ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_non_nullable"); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Take_without_orderby_followed_by_orderBy_is_pushed_down1(bool async) + { + return base.Take_without_orderby_followed_by_orderBy_is_pushed_down1(async); + } + + [Theory(Skip = "Different implicit ordering on Firebird.")] + [MemberData(nameof(IsAsyncData))] + public override Task Take_without_orderby_followed_by_orderBy_is_pushed_down2(bool async) + { + return base.Take_without_orderby_followed_by_orderBy_is_pushed_down2(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs new file mode 100644 index 000000000..eb47f9bd4 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixture.cs @@ -0,0 +1,23 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCInheritanceQueryFbFixture : TPCInheritanceQueryFbFixtureBase +{ + protected override bool UseGeneratedKeys => true; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixtureBase.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixtureBase.cs new file mode 100644 index 000000000..0c028635a --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbFixtureBase.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public abstract class TPCInheritanceQueryFbFixtureBase : TPCInheritanceQueryFixture +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs new file mode 100644 index 000000000..36c293304 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTest.cs @@ -0,0 +1,25 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCInheritanceQueryFbTest : TPCInheritanceQueryFbTestBase +{ + public TPCInheritanceQueryFbTest(TPCInheritanceQueryFbFixture fixture) + : base(fixture) + { } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs new file mode 100644 index 000000000..71ed94862 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryFbTestBase.cs @@ -0,0 +1,29 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore.Query; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public abstract class TPCInheritanceQueryFbTestBase : TPCInheritanceQueryTestBase + where TFixture : TPCInheritanceQueryFbFixtureBase, new() +{ + protected TPCInheritanceQueryFbTestBase(TFixture fixture) + : base(fixture) + { } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbFixture.cs new file mode 100644 index 000000000..bf9dfc1ae --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbFixture.cs @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCInheritanceQueryHiLoFbFixture : TPCInheritanceQueryFbFixtureBase +{ + protected override string StoreName => "TPCHiLoInheritanceTest"; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + modelBuilder.UseHiLo(); + + base.OnModelCreating(modelBuilder, context); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs new file mode 100644 index 000000000..1edcc7360 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCInheritanceQueryHiLoFbTest.cs @@ -0,0 +1,25 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCInheritanceQueryHiLoFbTest : TPCInheritanceQueryFbTestBase +{ + public TPCInheritanceQueryHiLoFbTest(TPCInheritanceQueryHiLoFbFixture fixture) + : base(fixture) + { } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyNoTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyNoTrackingQueryFbTest.cs new file mode 100644 index 000000000..8af40881d --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyNoTrackingQueryFbTest.cs @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCManyToManyNoTrackingQueryFbTest : TPCManyToManyNoTrackingQueryRelationalTestBase +{ + public TPCManyToManyNoTrackingQueryFbTest(TPCManyToManyQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_navigation_order_by_single_or_default(bool async) + { + return base.Skip_navigation_order_by_single_or_default(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbFixture.cs new file mode 100644 index 000000000..57618e697 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbFixture.cs @@ -0,0 +1,35 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCManyToManyQueryFbFixture : TPCManyToManyQueryRelationalFixture +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.ShortenMM(modelBuilder); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbTest.cs new file mode 100644 index 000000000..be8654380 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCManyToManyQueryFbTest.cs @@ -0,0 +1,51 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using Microsoft.EntityFrameworkCore.Query; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCManyToManyQueryFbTest : TPCManyToManyQueryRelationalTestBase +{ + public TPCManyToManyQueryFbTest(TPCManyToManyQueryFbFixture fixture) + : base(fixture) + { } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Skip_navigation_order_by_single_or_default(bool async) + { + return base.Skip_navigation_order_by_single_or_default(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCRelationshipsQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCRelationshipsQueryFbTest.cs new file mode 100644 index 000000000..4c7bf745e --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPCRelationshipsQueryFbTest.cs @@ -0,0 +1,34 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class TPCRelationshipsQueryFbTest : TPCRelationshipsQueryTestBase +{ + public TPCRelationshipsQueryFbTest(TPCRelationshipsQueryFbFixture fixture) + : base(fixture) + { } + + public class TPCRelationshipsQueryFbFixture : TPCRelationshipsQueryRelationalFixture + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs index 98d869213..056de0575 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbFixture.cs @@ -15,11 +15,19 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.TestModels.InheritanceModel; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPTFiltersInheritanceQueryFbFixture : TPTInheritanceQueryFbFixture { protected override bool EnableFilters => true; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + modelBuilder.Entity().Property(x => x.Id).UseSequenceTrigger(); + modelBuilder.Entity().Property(x => x.Id).UseSequenceTrigger(); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbTest.cs index c2da59b6d..9868341ad 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTFiltersInheritanceQueryFbTest.cs @@ -15,13 +15,7 @@ //$Authors = Jiri Cincura (jiri@cincura.net) -using System; -using System.Data.Common; -using System.Threading.Tasks; -using FirebirdSql.Data.FirebirdClient; -using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs index 69683cf57..3f0dc80d6 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTGearsOfWarQueryFbTest.cs @@ -313,18 +313,25 @@ public override Task ToString_boolean_property_non_nullable(bool async) select w.IsAutomatic.ToString(), null, elementAsserter: (lhs, rhs) => { Assert.True(lhs.Equals(rhs, System.StringComparison.InvariantCultureIgnoreCase)); }, assertOrder: false, 0, "ToString_boolean_property_non_nullable"); } - [Theory(Skip = "NETProvider#1009")] + [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Where_TimeOnly_Add_TimeSpan(bool async) + public override Task Where_TimeOnly_subtract_TimeOnly(bool async) { - return base.Where_TimeOnly_Add_TimeSpan(async); + return base.Where_TimeOnly_subtract_TimeOnly(async); } [NotSupportedOnFirebirdTheory] [MemberData(nameof(IsAsyncData))] - public override Task Where_TimeOnly_subtract_TimeOnly(bool async) + public override Task Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(bool async) { - return base.Where_TimeOnly_subtract_TimeOnly(async); + return base.Correlated_collection_with_groupby_with_complex_grouping_key_not_projecting_identifier_column_with_group_aggregate_in_final_projection(async); + } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task DateTimeOffsetNow_minus_timespan(bool async) + { + return base.DateTimeOffsetNow_minus_timespan(async); } [Theory(Skip = "NETProvider#1008")] @@ -333,4 +340,11 @@ public override Task Where_TimeOnly_IsBetween(bool async) { return base.Where_TimeOnly_IsBetween(async); } + + [Theory(Skip = "NETProvider#1009")] + [MemberData(nameof(IsAsyncData))] + public override Task Where_TimeOnly_Add_TimeSpan(bool async) + { + return base.Where_TimeOnly_Add_TimeSpan(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbFixture.cs index dd8be47fd..bea2c6ac1 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTInheritanceQueryFbFixture.cs @@ -16,7 +16,9 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestModels.InheritanceModel; using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; @@ -24,4 +26,11 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPTInheritanceQueryFbFixture : TPTInheritanceQueryFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + modelBuilder.Entity().Property(x => x.Id).UseSequenceTrigger(); + modelBuilder.Entity().Property(x => x.Id).UseSequenceTrigger(); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyNoTrackingQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyNoTrackingQueryFbTest.cs index 862f0bc10..b5b2c3f5f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyNoTrackingQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyNoTrackingQueryFbTest.cs @@ -41,4 +41,11 @@ public override Task Skip_navigation_order_by_single_or_default(bool async) { return base.Skip_navigation_order_by_single_or_default(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbFixture.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbFixture.cs index 5ead6300a..c5ca9719d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbFixture.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbFixture.cs @@ -15,7 +15,9 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.TestUtilities; @@ -24,4 +26,10 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; public class TPTManyToManyQueryFbFixture : TPTManyToManyQueryRelationalFixture { protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.ShortenMM(modelBuilder); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbTest.cs index a3aca76b5..1b0f28147 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/TPTManyToManyQueryFbTest.cs @@ -41,4 +41,11 @@ public override Task Skip_navigation_order_by_single_or_default(bool async) { return base.Skip_navigation_order_by_single_or_default(async); } + + [NotSupportedOnFirebirdTheory] + [MemberData(nameof(IsAsyncData))] + public override Task Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(bool async) + { + return base.Filtered_include_skip_navigation_order_by_skip_take_then_include_skip_navigation_where_EF_Property(async); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ToSqlQueryFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ToSqlQueryFbTest.cs new file mode 100644 index 000000000..a11b0fde5 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/ToSqlQueryFbTest.cs @@ -0,0 +1,110 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; +using Xunit; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; + +public class ToSqlQueryFbTest : ToSqlQueryTestBase +{ + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + public override async Task Entity_type_with_navigation_mapped_to_SqlQuery(bool async) + { + var contextFactory = await InitializeAsync( + seed: c => + { + var author = new Author { Name = "Toast", Posts = { new Post { Title = "Sausages of the world!" } } }; + c.Add(author); + c.SaveChanges(); + + var postStat = new PostStat { Count = 10, Author = author }; + author.PostStat = postStat; + c.Add(postStat); + c.SaveChanges(); + }); + + using var context = contextFactory.CreateContext(); + + var authors = await + (from o in context.Authors + select new { Author = o, PostCount = o.PostStat!.Count }).ToListAsync(); + + Assert.Single(authors); + Assert.Equal("Toast", authors[0].Author.Name); + Assert.Equal(10, authors[0].PostCount); + } + + protected new class Context27629 : DbContext + { + public Context27629(DbContextOptions options) + : base(options) + { } + + public DbSet Authors + => Set(); + + public DbSet Posts + => Set(); + + public DbSet PostStats + => Set(); + + protected override void OnModelCreating(ModelBuilder modelBuilder) + { + modelBuilder.Entity( + builder => + { + builder.ToTable("Authors"); + builder.Property(o => o.Name).HasMaxLength(50); + }); + + modelBuilder.Entity( + builder => + { + builder.ToTable("Posts"); + builder.Property(o => o.Title).HasMaxLength(50); + builder.Property(o => o.Content).HasMaxLength(500); + + builder + .HasOne(o => o.Author) + .WithMany(o => o.Posts) + .HasForeignKey(o => o.AuthorId) + .OnDelete(DeleteBehavior.ClientCascade); + }); + + modelBuilder.Entity( + builder => + { + builder + .ToSqlQuery("SELECT * FROM \"PostStats\"") + .HasKey(o => o.AuthorId); + + builder + .HasOne(o => o.Author) + .WithOne().HasForeignKey(o => o.AuthorId) + .OnDelete(DeleteBehavior.ClientCascade); + }); + } + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/WarningsFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/WarningsFbTest.cs index a931fcdb7..080ad4ae1 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/WarningsFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/Query/WarningsFbTest.cs @@ -16,12 +16,13 @@ //$Authors = Jiri Cincura (jiri@cincura.net) using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.TestUtilities; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Query; -public class WarningsFbTest : WarningsTestBase +public class WarningsFbTest : WarningsTestBase> { - public WarningsFbTest(QueryNoClientEvalFbFixture fixture) + public WarningsFbTest(NorthwindQueryFbFixture fixture) : base(fixture) { } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestHelpers.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestHelpers.cs index 1fa18c875..569eb364e 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestHelpers.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestHelpers.cs @@ -24,7 +24,7 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; -public class FbTestHelpers : TestHelpers +public class FbTestHelpers : RelationalTestHelpers { protected FbTestHelpers() { } @@ -34,7 +34,7 @@ protected FbTestHelpers() public override IServiceCollection AddProviderServices(IServiceCollection services) => services.AddEntityFrameworkFirebird(); - public override void UseProviderOptions(DbContextOptionsBuilder optionsBuilder) + public override DbContextOptionsBuilder UseProviderOptions(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseFirebird(new FbConnection("database=localhost:_.fdb;user=sysdba;password=masterkey;charset=utf8")); #pragma warning disable EF1001 diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestStore.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestStore.cs index 3c662b4e8..b11c93c56 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestStore.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/TestUtilities/FbTestStore.cs @@ -51,13 +51,23 @@ public FbTestStore(string name, bool shared) protected override string OpenDelimiter => "\""; protected override string CloseDelimiter => "\""; + public Version ServerVersion { get; private set; } + public bool ServerLessThan4() => ServerVersion < new Version(4, 0, 0, 0); + protected override void Initialize(Func createContext, Action seed, Action clean) { using (var context = createContext()) { // create database explicitly to specify Page Size and Forced Writes FbConnection.CreateDatabase(ConnectionString, pageSize: 16384, forcedWrites: false, overwrite: true); - context.Database.EnsureCreated(); + try + { + context.Database.EnsureCreated(); + } + catch (FbException ex) when (ServerLessThan4() && ex.Message.EndsWith("Name longer than database column size", StringComparison.Ordinal)) + { + return; + } clean?.Invoke(context); Clean(context); seed?.Invoke(context); @@ -67,7 +77,8 @@ protected override void Initialize(Func createContext, Action= new Version(4, 0, 0, 0)) + ServerVersion = FbServerProperties.ParseServerVersion(Connection.ServerVersion); + if (ServerVersion >= new Version(4, 0, 0, 0)) { using (var cmd = Connection.CreateCommand()) { diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbTest.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbTest.cs index 9743965d9..3ede018ee 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbTest.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests/UpdatesFbTest.cs @@ -15,19 +15,25 @@ //$Authors = Jiri Cincura (jiri@cincura.net) +using System; using System.Linq; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.Helpers; +using FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests.TestUtilities; +using FirebirdSql.EntityFrameworkCore.Firebird.Metadata; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.TestModels.UpdatesModel; +using Microsoft.EntityFrameworkCore.TestUtilities; using Xunit; namespace FirebirdSql.EntityFrameworkCore.Firebird.FunctionalTests; -public class UpdatesFbTest : UpdatesRelationalTestBase +public class UpdatesFbTest : UpdatesRelationalTestBase { public UpdatesFbTest(UpdatesFbFixture fixture) : base(fixture) { } + [Fact] public override void Identifiers_are_generated_correctly() { using (var context = CreateContext()) @@ -47,4 +53,20 @@ public override void Identifiers_are_generated_correctly() entityType.GetIndexes().Single().GetDatabaseName()); } } + + [Fact(Skip = "Uses type of filtered index that is not supported on Firebird.")] + public override void Swap_filtered_unique_index_values() => base.Swap_filtered_unique_index_values(); + + public class UpdatesFbFixture : UpdatesRelationalFixture + { + protected override ITestStoreFactory TestStoreFactory => FbTestStoreFactory.Instance; + + protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext context) + { + base.OnModelCreating(modelBuilder, context); + ModelHelpers.SetStringLengths(modelBuilder); + ModelHelpers.SetPrimaryKeyGeneration(modelBuilder, FbValueGenerationStrategy.IdentityColumn, x => x.ClrType == typeof(Person)); + modelBuilder.Entity(); + } + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj index e1b75086a..bcb38dba7 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/FirebirdSql.EntityFrameworkCore.Firebird.Tests.csproj @@ -1,6 +1,6 @@  - net6.0 + net7.0 false false true @@ -22,7 +22,7 @@ - + diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbDatabaseFacadeExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbDatabaseFacadeExtensions.cs index b4fbe2a40..0e76f4242 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbDatabaseFacadeExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbDatabaseFacadeExtensions.cs @@ -1,12 +1,28 @@ -using System.Reflection; +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Reflection; using FirebirdSql.EntityFrameworkCore.Firebird.Infrastructure.Internal; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; namespace FirebirdSql.EntityFrameworkCore.Firebird.Extensions; -using System; - /// /// FirebirdSQL specific extension methods for . /// diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelBuilderExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelBuilderExtensions.cs index 5a31af446..aa172b1f4 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelBuilderExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelBuilderExtensions.cs @@ -37,6 +37,37 @@ public static ModelBuilder UseSequenceTriggers(this ModelBuilder modelBuilder) return modelBuilder; } + public static ModelBuilder UseHiLo(this ModelBuilder modelBuilder, string name = null) + { + var model = modelBuilder.Model; + name ??= FbModelExtensions.DefaultHiLoSequenceName; + if (model.FindSequence(name) == null) + { + modelBuilder.HasSequence(name).IncrementsBy(10); + } + model.SetValueGenerationStrategy(FbValueGenerationStrategy.HiLo); + model.SetHiLoSequenceName(name); + model.SetSequenceNameSuffix(null); + return modelBuilder; + } + + public static IConventionSequenceBuilder HasHiLoSequence(this IConventionModelBuilder modelBuilder, string name, bool fromDataAnnotation = false) + { + if (!modelBuilder.CanSetHiLoSequence(name)) + { + return null; + } + modelBuilder.Metadata.SetHiLoSequenceName(name, fromDataAnnotation); + return name == null + ? null + : modelBuilder.HasSequence(name, null, fromDataAnnotation); + } + + public static bool CanSetHiLoSequence(this IConventionModelBuilder modelBuilder, string name, bool fromDataAnnotation = false) + { + return modelBuilder.CanSetAnnotation(FbAnnotationNames.HiLoSequenceName, name, fromDataAnnotation); + } + public static IConventionModelBuilder HasValueGenerationStrategy(this IConventionModelBuilder modelBuilder, FbValueGenerationStrategy? valueGenerationStrategy, bool fromDataAnnotation = false) { if (modelBuilder.CanSetAnnotation(FbAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy, fromDataAnnotation)) @@ -48,6 +79,9 @@ public static IConventionModelBuilder HasValueGenerationStrategy(this IConventio if (valueGenerationStrategy != FbValueGenerationStrategy.SequenceTrigger) { } + if (valueGenerationStrategy != FbValueGenerationStrategy.HiLo) + { + } return modelBuilder; } return null; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelExtensions.cs index a06d8aa87..3df6b288d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbModelExtensions.cs @@ -23,6 +23,9 @@ namespace Microsoft.EntityFrameworkCore; public static class FbModelExtensions { + public const string DefaultHiLoSequenceName = "EntityFrameworkHiLoSequence"; + public const string DefaultSequenceNameSuffix = "Sequence"; + public static void SetValueGenerationStrategy(this IMutableModel model, FbValueGenerationStrategy? value) => model.SetOrRemoveAnnotation(FbAnnotationNames.ValueGenerationStrategy, value); @@ -37,4 +40,52 @@ public static void SetValueGenerationStrategy(this IConventionModel model, FbVal public static FbValueGenerationStrategy? GetValueGenerationStrategy(this IConventionModel model) => (FbValueGenerationStrategy?)model[FbAnnotationNames.ValueGenerationStrategy]; + + public static string GetHiLoSequenceName(this IReadOnlyModel model) + => (string)model[FbAnnotationNames.HiLoSequenceName] ?? DefaultHiLoSequenceName; + + public static void SetHiLoSequenceName(this IMutableModel model, string name) + => model.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceName, name); + + public static string SetHiLoSequenceName(this IConventionModel model, string name, bool fromDataAnnotation = false) + => (string)model.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceName, name, fromDataAnnotation)?.Value; + + public static ConfigurationSource? GetHiLoSequenceNameConfigurationSource(this IConventionModel model) + => model.FindAnnotation(FbAnnotationNames.HiLoSequenceName)?.GetConfigurationSource(); + + public static string GetHiLoSequenceSchema(this IReadOnlyModel model) + => (string)model[FbAnnotationNames.HiLoSequenceSchema]; + + public static void SetHiLoSequenceSchema(this IMutableModel model, string value) + => model.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceSchema, value); + + public static string SetHiLoSequenceSchema(this IConventionModel model, string value, bool fromDataAnnotation = false) + => (string)model.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceSchema, value, fromDataAnnotation)?.Value; + + public static ConfigurationSource? GetHiLoSequenceSchemaConfigurationSource(this IConventionModel model) + => model.FindAnnotation(FbAnnotationNames.HiLoSequenceSchema)?.GetConfigurationSource(); + + public static string GetSequenceNameSuffix(this IReadOnlyModel model) + => (string)model[FbAnnotationNames.SequenceNameSuffix] ?? DefaultSequenceNameSuffix; + + public static void SetSequenceNameSuffix(this IMutableModel model, string name) + => model.SetOrRemoveAnnotation(FbAnnotationNames.SequenceNameSuffix, name); + + public static string SetSequenceNameSuffix(this IConventionModel model, string name, bool fromDataAnnotation = false) + => (string)model.SetOrRemoveAnnotation(FbAnnotationNames.SequenceNameSuffix, name, fromDataAnnotation)?.Value; + + public static ConfigurationSource? GetSequenceNameSuffixConfigurationSource(this IConventionModel model) + => model.FindAnnotation(FbAnnotationNames.SequenceNameSuffix)?.GetConfigurationSource(); + + public static string GetSequenceSchema(this IReadOnlyModel model) + => (string)model[FbAnnotationNames.SequenceSchema]; + + public static void SetSequenceSchema(this IMutableModel model, string value) + => model.SetOrRemoveAnnotation(FbAnnotationNames.SequenceSchema, value); + + public static string SetSequenceSchema(this IConventionModel model, string value, bool fromDataAnnotation = false) + => (string)model.SetOrRemoveAnnotation(FbAnnotationNames.SequenceSchema, value, fromDataAnnotation)?.Value; + + public static ConfigurationSource? GetSequenceSchemaConfigurationSource(this IConventionModel model) + => model.FindAnnotation(FbAnnotationNames.SequenceSchema)?.GetConfigurationSource(); } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyBuilderExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyBuilderExtensions.cs index 1d1ea6958..b7f696f66 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyBuilderExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyBuilderExtensions.cs @@ -43,6 +43,40 @@ public static PropertyBuilder UseSequenceTrigger(this PropertyBuilder propertyBu public static PropertyBuilder UseSequenceTrigger(this PropertyBuilder propertyBuilder) => (PropertyBuilder)UseSequenceTrigger((PropertyBuilder)propertyBuilder); + public static PropertyBuilder UseHiLo(this PropertyBuilder propertyBuilder, string name = null) + { + var property = propertyBuilder.Metadata; + name ??= FbModelExtensions.DefaultHiLoSequenceName; + var model = property.DeclaringType.Model; + if (model.FindSequence(name) == null) + { + model.AddSequence(name).IncrementBy = 10; + } + property.SetValueGenerationStrategy(FbValueGenerationStrategy.HiLo); + property.SetHiLoSequenceName(name); + return propertyBuilder; + } + + public static PropertyBuilder UseHiLo(this PropertyBuilder propertyBuilder, string name = null) + => (PropertyBuilder)UseHiLo((PropertyBuilder)propertyBuilder, name); + + public static IConventionSequenceBuilder HasHiLoSequence(this IConventionPropertyBuilder propertyBuilder, string name, bool fromDataAnnotation = false) + { + if (!propertyBuilder.CanSetHiLoSequence(name, fromDataAnnotation)) + { + return null; + } + propertyBuilder.Metadata.SetHiLoSequenceName(name, fromDataAnnotation); + return name == null + ? null + : propertyBuilder.Metadata.DeclaringType.Model.Builder.HasSequence(name, null, fromDataAnnotation); + } + + public static bool CanSetHiLoSequence(this IConventionPropertyBuilder propertyBuilder, string name, bool fromDataAnnotation = false) + { + return propertyBuilder.CanSetAnnotation(FbAnnotationNames.HiLoSequenceName, name, fromDataAnnotation); + } + public static IConventionPropertyBuilder HasValueGenerationStrategy(this IConventionPropertyBuilder propertyBuilder, FbValueGenerationStrategy? valueGenerationStrategy, bool fromDataAnnotation = false) { if (propertyBuilder.CanSetAnnotation(FbAnnotationNames.ValueGenerationStrategy, valueGenerationStrategy, fromDataAnnotation)) @@ -54,6 +88,9 @@ public static IConventionPropertyBuilder HasValueGenerationStrategy(this IConven if (valueGenerationStrategy != FbValueGenerationStrategy.SequenceTrigger) { } + if (valueGenerationStrategy != FbValueGenerationStrategy.HiLo) + { + } return propertyBuilder; } return null; diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs index 62fa02b6a..85ab07c86 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbPropertyExtensions.cs @@ -47,9 +47,20 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IPropert { return FbValueGenerationStrategy.SequenceTrigger; } - if (modelStrategy == FbValueGenerationStrategy.IdentityColumn && IsCompatibleIdentityColumn(property)) + if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) { - return FbValueGenerationStrategy.IdentityColumn; + if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + { + return FbValueGenerationStrategy.SequenceTrigger; + } + else if (IsCompatibleIdentityColumn(property)) + { + return FbValueGenerationStrategy.IdentityColumn; + } + } + if (modelStrategy == FbValueGenerationStrategy.HiLo && IsCompatibleHiLoColumn(property)) + { + return FbValueGenerationStrategy.HiLo; } return FbValueGenerationStrategy.None; @@ -78,9 +89,20 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IMutable { return FbValueGenerationStrategy.SequenceTrigger; } - if (modelStrategy == FbValueGenerationStrategy.IdentityColumn && IsCompatibleIdentityColumn(property)) + if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) + { + if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + { + return FbValueGenerationStrategy.SequenceTrigger; + } + else if (IsCompatibleIdentityColumn(property)) + { + return FbValueGenerationStrategy.IdentityColumn; + } + } + if (modelStrategy == FbValueGenerationStrategy.HiLo && IsCompatibleHiLoColumn(property)) { - return FbValueGenerationStrategy.IdentityColumn; + return FbValueGenerationStrategy.HiLo; } return FbValueGenerationStrategy.None; @@ -109,16 +131,29 @@ public static FbValueGenerationStrategy GetValueGenerationStrategy(this IConvent { return FbValueGenerationStrategy.SequenceTrigger; } - if (modelStrategy == FbValueGenerationStrategy.IdentityColumn && IsCompatibleIdentityColumn(property)) + if (modelStrategy == FbValueGenerationStrategy.IdentityColumn) + { + if (property.DeclaringEntityType.GetMappingStrategy() == RelationalAnnotationNames.TpcMappingStrategy) + { + return FbValueGenerationStrategy.SequenceTrigger; + } + else if (IsCompatibleIdentityColumn(property)) + { + return FbValueGenerationStrategy.IdentityColumn; + } + } + if (modelStrategy == FbValueGenerationStrategy.HiLo && IsCompatibleHiLoColumn(property)) { - return FbValueGenerationStrategy.IdentityColumn; + return FbValueGenerationStrategy.HiLo; } return FbValueGenerationStrategy.None; } public static ConfigurationSource? GetValueGenerationStrategyConfigurationSource(this IConventionProperty property) - => property.FindAnnotation(FbAnnotationNames.ValueGenerationStrategy)?.GetConfigurationSource(); + { + return property.FindAnnotation(FbAnnotationNames.ValueGenerationStrategy)?.GetConfigurationSource(); + } public static void SetValueGenerationStrategy(this IMutableProperty property, FbValueGenerationStrategy? value) { @@ -132,6 +167,202 @@ public static void SetValueGenerationStrategy(this IConventionProperty property, property.SetOrRemoveAnnotation(FbAnnotationNames.ValueGenerationStrategy, value, fromDataAnnotation); } + public static string GetHiLoSequenceName(this IReadOnlyProperty property) + { + return (string)property[FbAnnotationNames.HiLoSequenceName]; + } + + public static string GetHiLoSequenceName(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var annotation = property.FindAnnotation(FbAnnotationNames.HiLoSequenceName); + if (annotation != null) + { + return (string)annotation.Value; + } + + return property.FindSharedStoreObjectRootProperty(storeObject)?.GetHiLoSequenceName(storeObject); + } + + public static void SetHiLoSequenceName(this IMutableProperty property, string name) + { + property.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceName, name); + } + + public static string SetHiLoSequenceName(this IConventionProperty property, string name, bool fromDataAnnotation = false) + { + return (string)property.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceName, name, fromDataAnnotation)?.Value; + } + + public static ConfigurationSource? GetHiLoSequenceNameConfigurationSource(this IConventionProperty property) + { + return property.FindAnnotation(FbAnnotationNames.HiLoSequenceName)?.GetConfigurationSource(); + } + + public static string GetHiLoSequenceSchema(this IReadOnlyProperty property) + { + return (string)property[FbAnnotationNames.HiLoSequenceSchema]; + } + + public static string GetHiLoSequenceSchema(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var annotation = property.FindAnnotation(FbAnnotationNames.HiLoSequenceSchema); + if (annotation != null) + { + return (string)annotation.Value; + } + + return property.FindSharedStoreObjectRootProperty(storeObject)?.GetHiLoSequenceSchema(storeObject); + } + + public static void SetHiLoSequenceSchema(this IMutableProperty property, string schema) + { + property.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceSchema, schema); + } + + public static string SetHiLoSequenceSchema(this IConventionProperty property, string schema, bool fromDataAnnotation = false) + { + return (string)property.SetOrRemoveAnnotation(FbAnnotationNames.HiLoSequenceSchema, schema, fromDataAnnotation)?.Value; + } + + public static ConfigurationSource? GetHiLoSequenceSchemaConfigurationSource(this IConventionProperty property) + { + return property.FindAnnotation(FbAnnotationNames.HiLoSequenceSchema)?.GetConfigurationSource(); + } + + public static IReadOnlySequence FindHiLoSequence(this IReadOnlyProperty property) + { + var model = property.DeclaringEntityType.Model; + + var sequenceName = property.GetHiLoSequenceName() + ?? model.GetHiLoSequenceName(); + + var sequenceSchema = property.GetHiLoSequenceSchema() + ?? model.GetHiLoSequenceSchema(); + + return model.FindSequence(sequenceName, sequenceSchema); + } + + public static IReadOnlySequence FindHiLoSequence(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var model = property.DeclaringEntityType.Model; + + var sequenceName = property.GetHiLoSequenceName(storeObject) + ?? model.GetHiLoSequenceName(); + + var sequenceSchema = property.GetHiLoSequenceSchema(storeObject) + ?? model.GetHiLoSequenceSchema(); + + return model.FindSequence(sequenceName, sequenceSchema); + } + + public static ISequence FindHiLoSequence(this IProperty property) + { + return (ISequence)((IReadOnlyProperty)property).FindHiLoSequence(); + } + + public static ISequence FindHiLoSequence(this IProperty property, in StoreObjectIdentifier storeObject) + { + return (ISequence)((IReadOnlyProperty)property).FindHiLoSequence(storeObject); + } + + public static string GetSequenceName(this IReadOnlyProperty property) + { + return (string)property[FbAnnotationNames.SequenceName]; + } + + public static string GetSequenceName(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var annotation = property.FindAnnotation(FbAnnotationNames.SequenceName); + if (annotation != null) + { + return (string)annotation.Value; + } + + return property.FindSharedStoreObjectRootProperty(storeObject)?.GetSequenceName(storeObject); + } + + public static void SetSequenceName(this IMutableProperty property, string name) + { + property.SetOrRemoveAnnotation(FbAnnotationNames.SequenceName, name); + } + + public static string SetSequenceName(this IConventionProperty property, string name, bool fromDataAnnotation = false) + { + return (string)property.SetOrRemoveAnnotation(FbAnnotationNames.SequenceName, name, fromDataAnnotation)?.Value; + } + + public static ConfigurationSource? GetSequenceNameConfigurationSource(this IConventionProperty property) + { + return property.FindAnnotation(FbAnnotationNames.SequenceName)?.GetConfigurationSource(); + } + + public static string GetSequenceSchema(this IReadOnlyProperty property) + { + return (string)property[FbAnnotationNames.SequenceSchema]; + } + + public static string GetSequenceSchema(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var annotation = property.FindAnnotation(FbAnnotationNames.SequenceSchema); + if (annotation != null) + { + return (string)annotation.Value; + } + + return property.FindSharedStoreObjectRootProperty(storeObject)?.GetSequenceSchema(storeObject); + } + + public static void SetSequenceSchema(this IMutableProperty property, string schema) + { + property.SetOrRemoveAnnotation(FbAnnotationNames.SequenceSchema, schema); + } + + public static string SetSequenceSchema(this IConventionProperty property, string schema, bool fromDataAnnotation = false) + { + return (string)property.SetOrRemoveAnnotation(FbAnnotationNames.SequenceSchema, schema, fromDataAnnotation)?.Value; + } + + public static ConfigurationSource? GetSequenceSchemaConfigurationSource(this IConventionProperty property) + { + return property.FindAnnotation(FbAnnotationNames.SequenceSchema)?.GetConfigurationSource(); + } + + public static IReadOnlySequence FindSequence(this IReadOnlyProperty property) + { + var model = property.DeclaringEntityType.Model; + + var sequenceName = property.GetSequenceName() + ?? model.GetSequenceNameSuffix(); + + var sequenceSchema = property.GetSequenceSchema() + ?? model.GetSequenceSchema(); + + return model.FindSequence(sequenceName, sequenceSchema); + } + + public static IReadOnlySequence FindSequence(this IReadOnlyProperty property, in StoreObjectIdentifier storeObject) + { + var model = property.DeclaringEntityType.Model; + + var sequenceName = property.GetSequenceName(storeObject) + ?? model.GetSequenceNameSuffix(); + + var sequenceSchema = property.GetSequenceSchema(storeObject) + ?? model.GetSequenceSchema(); + + return model.FindSequence(sequenceName, sequenceSchema); + } + + public static ISequence FindSequence(this IProperty property) + { + return (ISequence)((IReadOnlyProperty)property).FindSequence(); + } + + public static ISequence FindSequence(this IProperty property, in StoreObjectIdentifier storeObject) + { + return (ISequence)((IReadOnlyProperty)property).FindSequence(storeObject); + } + static void CheckValueGenerationStrategy(IReadOnlyPropertyBase property, FbValueGenerationStrategy? value) { if (value != null) @@ -144,12 +375,25 @@ static void CheckValueGenerationStrategy(IReadOnlyPropertyBase property, FbValue { throw new ArgumentException($"Incompatible data type for {nameof(FbValueGenerationStrategy.SequenceTrigger)} for '{property.Name}'."); } + if (value == FbValueGenerationStrategy.HiLo && !IsCompatibleHiLoColumn(property)) + { + throw new ArgumentException($"Incompatible data type for {nameof(FbValueGenerationStrategy.HiLo)} for '{property.Name}'."); + } } } static bool IsCompatibleIdentityColumn(IReadOnlyPropertyBase property) - => property.ClrType.IsInteger() || property.ClrType == typeof(decimal); + { + return property.ClrType.IsInteger() || property.ClrType == typeof(decimal); + } static bool IsCompatibleSequenceTrigger(IReadOnlyPropertyBase property) - => true; + { + return true; + } + + static bool IsCompatibleHiLoColumn(IReadOnlyPropertyBase property) + { + return property.ClrType.IsInteger() || property.ClrType == typeof(decimal); + } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs index 1dfaeb070..505eeb563 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Extensions/FbServiceCollectionExtensions.cs @@ -29,6 +29,7 @@ using FirebirdSql.EntityFrameworkCore.Firebird.Query.Internal; using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; using FirebirdSql.EntityFrameworkCore.Firebird.Update.Internal; +using FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Metadata; @@ -37,6 +38,7 @@ using Microsoft.EntityFrameworkCore.Query; using Microsoft.EntityFrameworkCore.Storage; using Microsoft.EntityFrameworkCore.Update; +using Microsoft.EntityFrameworkCore.ValueGeneration; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.EntityFrameworkCore; @@ -59,13 +61,16 @@ public static IServiceCollection AddEntityFrameworkFirebird(this IServiceCollect var builder = new EntityFrameworkRelationalServicesBuilder(serviceCollection) .TryAdd() .TryAdd>() + .TryAdd(p => p.GetRequiredService()) .TryAdd() .TryAdd() .TryAdd() .TryAdd() + .TryAdd() .TryAdd() .TryAdd(p => p.GetService()) .TryAdd() + .TryAdd() .TryAdd(p => p.GetService()) .TryAdd() .TryAdd() @@ -80,6 +85,8 @@ public static IServiceCollection AddEntityFrameworkFirebird(this IServiceCollect .TryAddSingleton() .TryAddSingleton() .TryAddSingleton() + .TryAddSingleton() + .TryAddSingleton() .TryAddScoped() .TryAddScoped()); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj index 078172155..1991916c0 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/FirebirdSql.EntityFrameworkCore.Firebird.csproj @@ -10,7 +10,7 @@ NETProvider - Entity Framework Core Provider - (c) 2017-2021 + (c) 2017-2023 FirebirdSql.EntityFrameworkCore.Firebird @@ -29,8 +29,7 @@ - - + diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs new file mode 100644 index 000000000..55581b406 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Infrastructure/Internal/FbModelValidator.cs @@ -0,0 +1,43 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Linq; +using FirebirdSql.EntityFrameworkCore.Firebird.Metadata; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.Infrastructure.Internal; + +public class FbModelValidator : RelationalModelValidator +{ + public FbModelValidator(ModelValidatorDependencies dependencies, RelationalModelValidatorDependencies relationalDependencies) + : base(dependencies, relationalDependencies) + { } + + protected override void ValidateValueGeneration(IEntityType entityType, IKey key, IDiagnosticsLogger logger) + { + if (entityType.GetTableName() != null && (string)entityType[RelationalAnnotationNames.MappingStrategy] == RelationalAnnotationNames.TpcMappingStrategy) + { + foreach (var storeGeneratedProperty in key.Properties.Where(p => (p.ValueGenerated & ValueGenerated.OnAdd) != 0 && p.GetValueGenerationStrategy() == FbValueGenerationStrategy.IdentityColumn)) + { + logger.TpcStoreGeneratedIdentityWarning(storeGeneratedProperty); + } + } + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbConventionSetBuilder.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbConventionSetBuilder.cs index 1a20f9f0c..69bdc9821 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbConventionSetBuilder.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbConventionSetBuilder.cs @@ -32,24 +32,14 @@ public override ConventionSet CreateConventionSet() { var conventionSet = base.CreateConventionSet(); - var valueGenerationStrategyConvention = new FbValueGenerationStrategyConvention(Dependencies, RelationalDependencies); - conventionSet.ModelInitializedConventions.Add(valueGenerationStrategyConvention); - conventionSet.ModelInitializedConventions.Add(new RelationalMaxIdentifierLengthConvention(31, Dependencies, RelationalDependencies)); + conventionSet.Add(new FbValueGenerationStrategyConvention(Dependencies, RelationalDependencies)); + conventionSet.Add(new RelationalMaxIdentifierLengthConvention(31, Dependencies, RelationalDependencies)); - var valueGenerationConvention = new FbValueGenerationConvention(Dependencies, RelationalDependencies); - ReplaceConvention(conventionSet.EntityTypeBaseTypeChangedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.EntityTypePrimaryKeyChangedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.ForeignKeyAddedConventions, valueGenerationConvention); - ReplaceConvention(conventionSet.ForeignKeyRemovedConventions, valueGenerationConvention); - - var storeGenerationConvention = new FbStoreGenerationConvention(Dependencies, RelationalDependencies); - ReplaceConvention(conventionSet.PropertyAnnotationChangedConventions, storeGenerationConvention); - ReplaceConvention(conventionSet.PropertyAnnotationChangedConventions, (RelationalValueGenerationConvention)valueGenerationConvention); - - conventionSet.ModelFinalizingConventions.Add(valueGenerationStrategyConvention); - ReplaceConvention(conventionSet.ModelFinalizingConventions, storeGenerationConvention); + conventionSet.Replace(new FbStoreGenerationConvention(Dependencies, RelationalDependencies)); + conventionSet.Replace(new FbValueGenerationConvention(Dependencies, RelationalDependencies)); return conventionSet; + } public static ConventionSet Build() diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbStoreGenerationConvention.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbStoreGenerationConvention.cs index 20c7be3fa..41b70cc23 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbStoreGenerationConvention.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Conventions/FbStoreGenerationConvention.cs @@ -73,8 +73,8 @@ public override void ProcessPropertyAnnotationChanged(IConventionPropertyBuilder break; case FbAnnotationNames.ValueGenerationStrategy: if ((propertyBuilder.HasDefaultValue(null, fromDataAnnotation) == null - | propertyBuilder.HasDefaultValueSql(null, fromDataAnnotation) == null - | propertyBuilder.HasComputedColumnSql(null, fromDataAnnotation) == null) + || propertyBuilder.HasDefaultValueSql(null, fromDataAnnotation) == null + || propertyBuilder.HasComputedColumnSql(null, fromDataAnnotation) == null) && propertyBuilder.HasValueGenerationStrategy(null, fromDataAnnotation) != null) { context.StopProcessing(); @@ -89,28 +89,19 @@ public override void ProcessPropertyAnnotationChanged(IConventionPropertyBuilder protected override void Validate(IConventionProperty property, in StoreObjectIdentifier storeObject) { - if (property.GetValueGenerationStrategyConfigurationSource() != null - && property.GetValueGenerationStrategy() != FbValueGenerationStrategy.None) + if (property.GetValueGenerationStrategyConfigurationSource() != null && property.GetValueGenerationStrategy() != FbValueGenerationStrategy.None) { - if (property.GetDefaultValue() != null) + if (property.TryGetDefaultValue(storeObject, out _)) { - throw new InvalidOperationException( - RelationalStrings.ConflictingColumnServerGeneration( - nameof(FbValueGenerationStrategy), property.Name, "DefaultValue")); + throw new InvalidOperationException(RelationalStrings.ConflictingColumnServerGeneration(nameof(FbValueGenerationStrategy), property.Name, "DefaultValue")); } - if (property.GetDefaultValueSql() != null) { - throw new InvalidOperationException( - RelationalStrings.ConflictingColumnServerGeneration( - nameof(FbValueGenerationStrategy), property.Name, "DefaultValueSql")); + throw new InvalidOperationException(RelationalStrings.ConflictingColumnServerGeneration(nameof(FbValueGenerationStrategy), property.Name, "DefaultValueSql")); } - if (property.GetComputedColumnSql() != null) { - throw new InvalidOperationException( - RelationalStrings.ConflictingColumnServerGeneration( - nameof(FbValueGenerationStrategy), property.Name, "ComputedColumnSql")); + throw new InvalidOperationException(RelationalStrings.ConflictingColumnServerGeneration(nameof(FbValueGenerationStrategy), property.Name, "ComputedColumnSql")); } } base.Validate(property, storeObject); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/FbValueGenerationStrategy.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/FbValueGenerationStrategy.cs index e79e403c0..e1203a237 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/FbValueGenerationStrategy.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/FbValueGenerationStrategy.cs @@ -22,4 +22,5 @@ public enum FbValueGenerationStrategy None, SequenceTrigger, IdentityColumn, + HiLo, } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Internal/FbAnnotationNames.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Internal/FbAnnotationNames.cs index 06d0e9469..b4483d141 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Internal/FbAnnotationNames.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Metadata/Internal/FbAnnotationNames.cs @@ -21,4 +21,9 @@ public static class FbAnnotationNames { public const string Prefix = "Fb:"; public const string ValueGenerationStrategy = Prefix + nameof(ValueGenerationStrategy); + public const string HiLoSequenceName = Prefix + nameof(HiLoSequenceName); + public const string HiLoSequenceSchema = Prefix + nameof(HiLoSequenceSchema); + public const string SequenceName = Prefix + nameof(SequenceName); + public const string SequenceSchema = Prefix + nameof(SequenceSchema); + public const string SequenceNameSuffix = Prefix+ nameof(SequenceNameSuffix); } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs index eccc281e8..cda1862f3 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Migrations/FbMigrationsSqlGenerator.cs @@ -19,6 +19,7 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; +using System.Text; using FirebirdSql.Data.FirebirdClient; using FirebirdSql.EntityFrameworkCore.Firebird.Infrastructure.Internal; using FirebirdSql.EntityFrameworkCore.Firebird.Metadata; @@ -28,6 +29,7 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Update; namespace FirebirdSql.EntityFrameworkCore.Firebird.Migrations; @@ -375,6 +377,54 @@ protected override void ForeignKeyConstraint(AddForeignKeyOperation operation, I } } + protected override void Generate(InsertDataOperation operation, IModel model, MigrationCommandListBuilder builder, bool terminate = true) + { + var sqlBuilder = new StringBuilder(); + foreach (var modificationCommand in GenerateModificationCommands(operation, model)) + { + SqlGenerator.AppendInsertOperation( + sqlBuilder, + modificationCommand, + 0); + builder.Append(sqlBuilder.ToString()); + if (terminate) + { + EndStatement(builder); + } + sqlBuilder.Clear(); + } + } + + protected override void Generate(DeleteDataOperation operation, IModel model, MigrationCommandListBuilder builder) + { + var sqlBuilder = new StringBuilder(); + foreach (var modificationCommand in GenerateModificationCommands(operation, model)) + { + SqlGenerator.AppendDeleteOperation( + sqlBuilder, + modificationCommand, + 0); + builder.Append(sqlBuilder.ToString()); + EndStatement(builder); + sqlBuilder.Clear(); + } + } + + protected override void Generate(UpdateDataOperation operation, IModel model, MigrationCommandListBuilder builder) + { + var sqlBuilder = new StringBuilder(); + foreach (var modificationCommand in GenerateModificationCommands(operation, model)) + { + SqlGenerator.AppendUpdateOperation( + sqlBuilder, + modificationCommand, + 0); + builder.Append(sqlBuilder.ToString()); + EndStatement(builder); + sqlBuilder.Clear(); + } + } + protected override void ForeignKeyAction(ReferentialAction referentialAction, MigrationCommandListBuilder builder) { switch (referentialAction) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbConvertTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbConvertTranslator.cs index 360db4fd2..891c73b51 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbConvertTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbConvertTranslator.cs @@ -20,7 +20,6 @@ using System.Linq; using System.Reflection; using FirebirdSql.EntityFrameworkCore.Firebird.Query.Internal; -using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Diagnostics; using Microsoft.EntityFrameworkCore.Query; @@ -39,6 +38,7 @@ public class FbConvertTranslator : IMethodCallTranslator nameof(Convert.ToInt32), nameof(Convert.ToInt64), nameof(Convert.ToString), + nameof(Convert.ToBoolean), }; static readonly HashSet SupportedTypes = new HashSet diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs index d1f5e0641..87ec77169 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringContainsTranslator.cs @@ -57,7 +57,7 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO : _fbSqlExpressionFactory.OrElse( positionExpression, _fbSqlExpressionFactory.Equal( - patternExpression, - _fbSqlExpressionFactory.Constant(string.Empty))); + _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), + _fbSqlExpressionFactory.Constant(0))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs index 900c6f3a3..a0353c0d6 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringEndsWithTranslator.cs @@ -64,7 +64,7 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO : _fbSqlExpressionFactory.OrElse( endsWithExpression, _fbSqlExpressionFactory.Equal( - patternExpression, - _fbSqlExpressionFactory.Constant(string.Empty))); + _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), + _fbSqlExpressionFactory.Constant(0))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringFirstOrDefaultTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringFirstOrDefaultTranslator.cs index 3696b670b..fea8d0025 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringFirstOrDefaultTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringFirstOrDefaultTranslator.cs @@ -50,6 +50,6 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO new[] { argument, _fbSqlExpressionFactory.Constant(1) }, true, new[] { true, false }, - typeof(string)); + method.ReturnType); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIndexOfTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIndexOfTranslator.cs index 866ba5e6f..84e212d6f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIndexOfTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIndexOfTranslator.cs @@ -28,6 +28,12 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.Query.ExpressionTranslators.I public class FbStringIndexOfTranslator : IMethodCallTranslator { + static readonly MethodInfo IndexOfMethodInfo + = typeof(string).GetRuntimeMethod(nameof(string.IndexOf), new[] { typeof(string) }); + + static readonly MethodInfo IndexOfMethodInfoWithStartingPosition + = typeof(string).GetRuntimeMethod(nameof(string.IndexOf), new[] { typeof(string), typeof(int) }); + readonly FbSqlExpressionFactory _fbSqlExpressionFactory; public FbStringIndexOfTranslator(FbSqlExpressionFactory fbSqlExpressionFactory) @@ -37,15 +43,21 @@ public FbStringIndexOfTranslator(FbSqlExpressionFactory fbSqlExpressionFactory) public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList arguments, IDiagnosticsLogger logger) { - if (method.DeclaringType == typeof(string) && method.Name == nameof(string.IndexOf)) + if (method.Equals(IndexOfMethodInfo)) + { + var args = new List(); + args.Add(_fbSqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0])); + args.Add(instance); + return _fbSqlExpressionFactory.Subtract( + _fbSqlExpressionFactory.Function("POSITION", args, true, Enumerable.Repeat(true, args.Count), typeof(int)), + _fbSqlExpressionFactory.Constant(1)); + } + if (method.Equals(IndexOfMethodInfoWithStartingPosition)) { var args = new List(); args.Add(_fbSqlExpressionFactory.ApplyDefaultTypeMapping(arguments[0])); args.Add(instance); - foreach (var a in arguments.Skip(1)) - { - args.Add(_fbSqlExpressionFactory.ApplyDefaultTypeMapping(a)); - } + args.Add(_fbSqlExpressionFactory.Add(arguments[1], _fbSqlExpressionFactory.Constant(1))); return _fbSqlExpressionFactory.Subtract( _fbSqlExpressionFactory.Function("POSITION", args, true, Enumerable.Repeat(true, args.Count), typeof(int)), _fbSqlExpressionFactory.Constant(1)); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIsNullOrWhiteSpaceTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIsNullOrWhiteSpaceTranslator.cs index b2efa1efe..8a946876a 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIsNullOrWhiteSpaceTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringIsNullOrWhiteSpaceTranslator.cs @@ -45,8 +45,9 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO return _fbSqlExpressionFactory.OrElse( _fbSqlExpressionFactory.IsNull(argument), _fbSqlExpressionFactory.Equal( - _fbSqlExpressionFactory.Function("TRIM", new[] { argument }, true, new[] { true }, typeof(string)), - _fbSqlExpressionFactory.Constant(string.Empty)) + _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { + _fbSqlExpressionFactory.Function("TRIM", new[] { argument }, true, new[] { true }, typeof(string)) }, true, new[] { true }, typeof(int)), + _fbSqlExpressionFactory.Constant(0)) ); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringLastOrDefaultTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringLastOrDefaultTranslator.cs index 81320dcfe..461da0218 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringLastOrDefaultTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringLastOrDefaultTranslator.cs @@ -50,6 +50,6 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO new[] { argument, _fbSqlExpressionFactory.Constant(1) }, true, new[] { true, false }, - typeof(string)); + method.ReturnType); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs index 9e308771d..b89294c30 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/ExpressionTranslators/Internal/FbStringStartsWithTranslator.cs @@ -72,7 +72,7 @@ public SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadO : _fbSqlExpressionFactory.OrElse( startsWithExpression, _fbSqlExpressionFactory.Equal( - patternExpression, - _fbSqlExpressionFactory.Constant(string.Empty))); + _fbSqlExpressionFactory.Function("CHAR_LENGTH", new[] { patternExpression }, true, new[] { true }, typeof(int)), + _fbSqlExpressionFactory.Constant(0))); } } diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs index 49b4d71e3..51268e4f3 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Query/Internal/FbQuerySqlGenerator.cs @@ -39,6 +39,21 @@ public FbQuerySqlGenerator(QuerySqlGeneratorDependencies dependencies, IFbOption _fbOptions = fbOptions; } + protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) + { + if (sqlUnaryExpression.OperatorType == ExpressionType.Not && sqlUnaryExpression.TypeMapping.ClrType != typeof(bool)) + { + Sql.Append("BIN_NOT("); + Visit(sqlUnaryExpression.Operand); + Sql.Append(")"); + return sqlUnaryExpression; + } + else + { + return base.VisitSqlUnary(sqlUnaryExpression); + } + } + protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression) { if (sqlBinaryExpression.OperatorType == ExpressionType.Modulo) @@ -143,6 +158,15 @@ protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstant return sqlConstantExpression; } + protected override void GenerateEmptyProjection(SelectExpression selectExpression) + { + base.GenerateEmptyProjection(selectExpression); + if (selectExpression.Alias != null) + { + Sql.Append(" AS empty"); + } + } + protected override void GenerateTop(SelectExpression selectExpression) { // handled by GenerateLimitOffset diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbProviderCodeGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbProviderCodeGenerator.cs index 66440e6ec..2f142eda9 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbProviderCodeGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbProviderCodeGenerator.cs @@ -27,11 +27,9 @@ namespace FirebirdSql.EntityFrameworkCore.Firebird.Scaffolding.Internal; public class FbProviderCodeGenerator : ProviderCodeGenerator { static readonly MethodInfo UseFirebirdMethodInfo - = typeof(FbDbContextOptionsBuilderExtensions).GetRequiredRuntimeMethod( + = typeof(FbDbContextOptionsBuilderExtensions).GetRuntimeMethod( nameof(FbDbContextOptionsBuilderExtensions.UseFirebird), - typeof(DbContextOptionsBuilder), - typeof(string), - typeof(Action)); + new[] { typeof(DbContextOptionsBuilder), typeof(string), typeof(Action) }); public FbProviderCodeGenerator(ProviderCodeGeneratorDependencies dependencies) : base(dependencies) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbDatabaseCreator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbDatabaseCreator.cs index 536126665..5c233f90d 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbDatabaseCreator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbDatabaseCreator.cs @@ -163,4 +163,4 @@ IRelationalCommand CreateAlterCollationCommand(string collation) BEGIN execute statement 'alter character set ' || (select coalesce(trim(rdb$character_set_name), 'NONE') from rdb$database) || ' set default collation {collation}'; END"); -} \ No newline at end of file +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs index caf449c90..3aa22fc4f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbSqlGenerationHelper.cs @@ -45,7 +45,7 @@ public virtual void GenerateBlockParameterName(StringBuilder builder, string nam builder.Append(":").Append(name); } - public string AlternativeStatementTerminator => "~"; + public virtual string AlternativeStatementTerminator => "~"; static int MinimumStringQueryTypeLength(string s) { diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs index 4efe08fc9..e4d85de9c 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Storage/Internal/FbTypeMappingSource.cs @@ -65,48 +65,48 @@ public FbTypeMappingSource(TypeMappingSourceDependencies dependencies, Relationa : base(dependencies, relationalDependencies) { _storeTypeMappings = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "BOOLEAN", _boolean }, - { "SMALLINT", _smallint }, - { "INTEGER", _integer }, - { "BIGINT", _bigint }, - { "CHAR", _char }, - { "VARCHAR", _varchar }, - { "BLOB SUB_TYPE TEXT", _clob }, - { "BLOB SUB_TYPE BINARY", _binary }, - { "FLOAT", _float }, - { "DOUBLE PRECISION", _double }, - { "DECIMAL", _decimal }, - { "TIMESTAMP", _timestamp }, - { "DATE", _date }, - { "TIME", _timeSpan }, - { "CHAR(16) CHARACTER SET OCTETS", _guid }, - }; + { + { "BOOLEAN", _boolean }, + { "SMALLINT", _smallint }, + { "INTEGER", _integer }, + { "BIGINT", _bigint }, + { "CHAR", _char }, + { "VARCHAR", _varchar }, + { "BLOB SUB_TYPE TEXT", _clob }, + { "BLOB SUB_TYPE BINARY", _binary }, + { "FLOAT", _float }, + { "DOUBLE PRECISION", _double }, + { "DECIMAL", _decimal }, + { "TIMESTAMP", _timestamp }, + { "DATE", _date }, + { "TIME", _timeSpan }, + { "CHAR(16) CHARACTER SET OCTETS", _guid }, + }; _clrTypeMappings = new Dictionary() - { - { typeof(bool), _boolean }, - { typeof(short), _smallint }, - { typeof(int), _integer }, - { typeof(long), _bigint }, - { typeof(float), _float }, - { typeof(double), _double}, - { typeof(decimal), _decimal }, - { typeof(DateTime), _timestamp }, - { typeof(TimeSpan), _timeSpan }, - { typeof(Guid), _guid }, - { typeof(DateOnly), _dateOnly }, - { typeof(TimeOnly), _timeOnly }, - }; + { + { typeof(bool), _boolean }, + { typeof(short), _smallint }, + { typeof(int), _integer }, + { typeof(long), _bigint }, + { typeof(float), _float }, + { typeof(double), _double}, + { typeof(decimal), _decimal }, + { typeof(DateTime), _timestamp }, + { typeof(TimeSpan), _timeSpan }, + { typeof(Guid), _guid }, + { typeof(DateOnly), _dateOnly }, + { typeof(TimeOnly), _timeOnly }, + }; _disallowedMappings = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "CHARACTER", - "CHAR", - "VARCHAR", - "CHARACTER VARYING", - "CHAR VARYING", - }; + { + "CHARACTER", + "CHAR", + "VARCHAR", + "CHARACTER VARYING", + "CHAR VARYING", + }; } protected override RelationalTypeMapping FindMapping(in RelationalTypeMappingInfo mappingInfo) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Update/Internal/FbUpdateSqlGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Update/Internal/FbUpdateSqlGenerator.cs index 79bda6d17..d3b36d050 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Update/Internal/FbUpdateSqlGenerator.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Update/Internal/FbUpdateSqlGenerator.cs @@ -32,15 +32,9 @@ public FbUpdateSqlGenerator(UpdateSqlGeneratorDependencies dependencies) : base(dependencies) { } - protected override void AppendIdentityWhereCondition(StringBuilder commandStringBuilder, IColumnModification columnModification) - => throw new InvalidOperationException(); - - protected override void AppendRowsAffectedWhereCondition(StringBuilder commandStringBuilder, int expectedRowsAffected) - => throw new InvalidOperationException(); - - public override ResultSetMapping AppendInsertOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) + public override ResultSetMapping AppendInsertOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, out bool requiresTransaction) { - var result = ResultSetMapping.NoResultSet; + var result = default(ResultSetMapping); var name = command.TableName; var operations = command.ColumnModifications; var writeOperations = operations.Where(o => o.IsWrite).ToList(); @@ -57,14 +51,21 @@ public override ResultSetMapping AppendInsertOperation(StringBuilder commandStri { b.Append(SqlGenerationHelper.DelimitIdentifier(e.ColumnName)); }, ", "); - result = ResultSetMapping.LastInResultSet; + result = ResultSetMapping.HasResultRow; + } + else + { + result = ResultSetMapping.NoResults; } commandStringBuilder.Append(SqlGenerationHelper.StatementTerminator).AppendLine(); + + requiresTransaction = true; return result; } - public override ResultSetMapping AppendUpdateOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) + public override ResultSetMapping AppendUpdateOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, out bool requiresTransaction) { + var result = default(ResultSetMapping); var name = command.TableName; var operations = command.ColumnModifications; var writeOperations = operations.Where(o => o.IsWrite).ToList(); @@ -121,18 +122,22 @@ public override ResultSetMapping AppendUpdateOperation(StringBuilder commandStri { commandStringBuilder.AppendLine("ROWS_AFFECTED = ROW_COUNT;"); commandStringBuilder.AppendLine("SUSPEND;"); + result = ResultSetMapping.ResultSetWithRowsAffectedOnly; } else { commandStringBuilder.AppendLine("IF (ROW_COUNT > 0) THEN"); commandStringBuilder.AppendLine("SUSPEND;"); + result = ResultSetMapping.HasResultRow; } commandStringBuilder.Append("END"); commandStringBuilder.Append(SqlGenerationHelper.StatementTerminator).AppendLine(); - return ResultSetMapping.LastInResultSet; + + requiresTransaction = true; + return result; } - public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition) + public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStringBuilder, IReadOnlyModificationCommand command, int commandPosition, out bool requiresTransaction) { var name = command.TableName; var operations = command.ColumnModifications; @@ -158,7 +163,9 @@ public override ResultSetMapping AppendDeleteOperation(StringBuilder commandStri commandStringBuilder.AppendLine("SUSPEND;"); commandStringBuilder.Append("END"); commandStringBuilder.Append(SqlGenerationHelper.StatementTerminator).AppendLine(); - return ResultSetMapping.LastInResultSet; + + requiresTransaction = true; + return ResultSetMapping.ResultSetWithRowsAffectedOnly; } // workaround for GenerateBlockParameterName diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/EnumerableMethods.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/EnumerableMethods.cs index da7500e1c..f9a6e12b3 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/EnumerableMethods.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/EnumerableMethods.cs @@ -1,14 +1,14 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Reflection; -#nullable enable - namespace Microsoft.EntityFrameworkCore; internal static class EnumerableMethods @@ -204,37 +204,40 @@ internal static class EnumerableMethods //public static MethodInfo Zip { get; } - private static Dictionary SumWithoutSelectorMethods { get; } + // private static Dictionary SumWithoutSelectorMethods { get; } private static Dictionary SumWithSelectorMethods { get; } - private static Dictionary AverageWithoutSelectorMethods { get; } + + // private static Dictionary AverageWithoutSelectorMethods { get; } private static Dictionary AverageWithSelectorMethods { get; } private static Dictionary MaxWithoutSelectorMethods { get; } private static Dictionary MaxWithSelectorMethods { get; } private static Dictionary MinWithoutSelectorMethods { get; } private static Dictionary MinWithSelectorMethods { get; } - public static bool IsSumWithoutSelector(MethodInfo methodInfo) - => SumWithoutSelectorMethods.Values.Contains(methodInfo); - - public static bool IsSumWithSelector(MethodInfo methodInfo) - => methodInfo.IsGenericMethod - && SumWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); - - public static bool IsAverageWithoutSelector(MethodInfo methodInfo) - => AverageWithoutSelectorMethods.Values.Contains(methodInfo); - - public static bool IsAverageWithSelector(MethodInfo methodInfo) - => methodInfo.IsGenericMethod - && AverageWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); - - public static MethodInfo GetSumWithoutSelector(Type type) - => SumWithoutSelectorMethods[type]; + // Not currently used + // + // public static bool IsSumWithoutSelector(MethodInfo methodInfo) + // => SumWithoutSelectorMethods.Values.Contains(methodInfo); + // + // public static bool IsSumWithSelector(MethodInfo methodInfo) + // => methodInfo.IsGenericMethod + // && SumWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); + // + // public static bool IsAverageWithoutSelector(MethodInfo methodInfo) + // => AverageWithoutSelectorMethods.Values.Contains(methodInfo); + // + // public static bool IsAverageWithSelector(MethodInfo methodInfo) + // => methodInfo.IsGenericMethod + // && AverageWithSelectorMethods.Values.Contains(methodInfo.GetGenericMethodDefinition()); + // + // public static MethodInfo GetSumWithoutSelector(Type type) + // => SumWithoutSelectorMethods[type]; public static MethodInfo GetSumWithSelector(Type type) => SumWithSelectorMethods[type]; - public static MethodInfo GetAverageWithoutSelector(Type type) - => AverageWithoutSelectorMethods[type]; + // public static MethodInfo GetAverageWithoutSelector(Type type) + // => AverageWithoutSelectorMethods[type]; public static MethodInfo GetAverageWithSelector(Type type) => AverageWithSelectorMethods[type]; @@ -268,11 +271,7 @@ static EnumerableMethods() All = GetMethod( nameof(Enumerable.All), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); AnyWithoutPredicate = GetMethod( nameof(Enumerable.Any), 1, @@ -280,33 +279,21 @@ static EnumerableMethods() AnyWithPredicate = GetMethod( nameof(Enumerable.Any), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); AsEnumerable = GetMethod( nameof(Enumerable.AsEnumerable), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); - Cast = GetMethod(nameof(Enumerable.Cast), 1, types => new[] { typeof(IEnumerable) }); + Cast = GetMethod(nameof(Enumerable.Cast), 1, _ => new[] { typeof(IEnumerable) }); Concat = GetMethod( nameof(Enumerable.Concat), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[0]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(IEnumerable<>).MakeGenericType(types[0]) }); Contains = GetMethod( nameof(Enumerable.Contains), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - types[0] - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), types[0] }); CountWithoutPredicate = GetMethod( nameof(Enumerable.Count), 1, @@ -314,11 +301,7 @@ static EnumerableMethods() CountWithPredicate = GetMethod( nameof(Enumerable.Count), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); DefaultIfEmptyWithoutArgument = GetMethod( nameof(Enumerable.DefaultIfEmpty), 1, @@ -326,48 +309,28 @@ static EnumerableMethods() DefaultIfEmptyWithArgument = GetMethod( nameof(Enumerable.DefaultIfEmpty), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - types[0] - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), types[0] }); Distinct = GetMethod(nameof(Enumerable.Distinct), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); ElementAt = GetMethod( nameof(Enumerable.ElementAt), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(int) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(int) }); ElementAtOrDefault = GetMethod( nameof(Enumerable.ElementAtOrDefault), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(int) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(int) }); Except = GetMethod( nameof(Enumerable.Except), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[0]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(IEnumerable<>).MakeGenericType(types[0]) }); FirstWithoutPredicate = GetMethod( nameof(Enumerable.First), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); FirstWithPredicate = GetMethod( nameof(Enumerable.First), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); FirstOrDefaultWithoutPredicate = GetMethod( nameof(Enumerable.FirstOrDefault), 1, @@ -375,79 +338,67 @@ static EnumerableMethods() FirstOrDefaultWithPredicate = GetMethod( nameof(Enumerable.FirstOrDefault), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); GroupByWithKeySelector = GetMethod( nameof(Enumerable.GroupBy), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); GroupByWithKeyElementSelector = GetMethod( nameof(Enumerable.GroupBy), 3, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]), - typeof(Func<,>).MakeGenericType(types[0], types[2]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]) }); GroupByWithKeyElementResultSelector = GetMethod( nameof(Enumerable.GroupBy), 4, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]), - typeof(Func<,>).MakeGenericType(types[0], types[2]), - typeof(Func<,,>).MakeGenericType( - types[1], typeof(IEnumerable<>).MakeGenericType(types[2]), types[3]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[2]), types[3]) }); GroupByWithKeyResultSelector = GetMethod( nameof(Enumerable.GroupBy), 3, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]), - typeof(Func<,,>).MakeGenericType( - types[1], typeof(IEnumerable<>).MakeGenericType(types[0]), types[2]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType(types[0], types[1]), + typeof(Func<,,>).MakeGenericType( + types[1], typeof(IEnumerable<>).MakeGenericType(types[0]), types[2]) }); GroupJoin = GetMethod( nameof(Enumerable.GroupJoin), 4, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[1]), - typeof(Func<,>).MakeGenericType(types[0], types[2]), - typeof(Func<,>).MakeGenericType(types[1], types[2]), - typeof(Func<,,>).MakeGenericType( - types[0], typeof(IEnumerable<>).MakeGenericType(types[1]), types[3]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,>).MakeGenericType(types[1], types[2]), + typeof(Func<,,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1]), types[3]) }); Intersect = GetMethod( nameof(Enumerable.Intersect), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[0]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(IEnumerable<>).MakeGenericType(types[0]) }); Join = GetMethod( nameof(Enumerable.Join), 4, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[1]), - typeof(Func<,>).MakeGenericType(types[0], types[2]), - typeof(Func<,>).MakeGenericType(types[1], types[2]), - typeof(Func<,,>).MakeGenericType(types[0], types[1], types[3]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(IEnumerable<>).MakeGenericType(types[1]), + typeof(Func<,>).MakeGenericType(types[0], types[2]), + typeof(Func<,>).MakeGenericType(types[1], types[2]), + typeof(Func<,,>).MakeGenericType(types[0], types[1], types[3]) }); LastWithoutPredicate = GetMethod( @@ -455,11 +406,7 @@ static EnumerableMethods() LastWithPredicate = GetMethod( nameof(Enumerable.Last), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); LastOrDefaultWithoutPredicate = GetMethod( nameof(Enumerable.LastOrDefault), 1, @@ -467,11 +414,7 @@ static EnumerableMethods() LastOrDefaultWithPredicate = GetMethod( nameof(Enumerable.LastOrDefault), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); LongCountWithoutPredicate = GetMethod( nameof(Enumerable.LongCount), 1, @@ -479,105 +422,72 @@ static EnumerableMethods() LongCountWithPredicate = GetMethod( nameof(Enumerable.LongCount), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); MaxWithoutSelector = GetMethod(nameof(Enumerable.Max), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); MaxWithSelector = GetMethod( nameof(Enumerable.Max), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); MinWithoutSelector = GetMethod(nameof(Enumerable.Min), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); MinWithSelector = GetMethod( nameof(Enumerable.Min), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); - OfType = GetMethod(nameof(Enumerable.OfType), 1, types => new[] { typeof(IEnumerable) }); + OfType = GetMethod(nameof(Enumerable.OfType), 1, _ => new[] { typeof(IEnumerable) }); OrderBy = GetMethod( nameof(Enumerable.OrderBy), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); OrderByDescending = GetMethod( nameof(Enumerable.OrderByDescending), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); Reverse = GetMethod(nameof(Enumerable.Reverse), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); Select = GetMethod( nameof(Enumerable.Select), 2, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); SelectWithOrdinal = GetMethod( nameof(Enumerable.Select), 2, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,,>).MakeGenericType(types[0], typeof(int), types[1]) + typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,,>).MakeGenericType(types[0], typeof(int), types[1]) }); SelectManyWithoutCollectionSelector = GetMethod( nameof(Enumerable.SelectMany), 2, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType( - types[0], typeof(IEnumerable<>).MakeGenericType(types[1])) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1])) }); SelectManyWithCollectionSelector = GetMethod( nameof(Enumerable.SelectMany), 3, types => new[] { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType( - types[0], typeof(IEnumerable<>).MakeGenericType(types[1])), - typeof(Func<,,>).MakeGenericType(types[0], types[1], types[2]) + typeof(IEnumerable<>).MakeGenericType(types[0]), + typeof(Func<,>).MakeGenericType( + types[0], typeof(IEnumerable<>).MakeGenericType(types[1])), + typeof(Func<,,>).MakeGenericType(types[0], types[1], types[2]) }); SequenceEqual = GetMethod( nameof(Enumerable.SequenceEqual), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[0]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(IEnumerable<>).MakeGenericType(types[0]) }); SingleWithoutPredicate = GetMethod( nameof(Enumerable.Single), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); SingleWithPredicate = GetMethod( nameof(Enumerable.Single), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); SingleOrDefaultWithoutPredicate = GetMethod( nameof(Enumerable.SingleOrDefault), 1, @@ -585,27 +495,15 @@ static EnumerableMethods() SingleOrDefaultWithPredicate = GetMethod( nameof(Enumerable.SingleOrDefault), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); Skip = GetMethod( nameof(Enumerable.Skip), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(int) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(int) }); SkipWhile = GetMethod( nameof(Enumerable.SkipWhile), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); ToArray = GetMethod(nameof(Enumerable.ToArray), 1, types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]) }); @@ -613,109 +511,73 @@ static EnumerableMethods() Take = GetMethod( nameof(Enumerable.Take), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(int) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(int) }); TakeWhile = GetMethod( nameof(Enumerable.TakeWhile), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); ThenBy = GetMethod( nameof(Enumerable.ThenBy), 2, - types => new[] - { - typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); ThenByDescending = GetMethod( nameof(Enumerable.ThenByDescending), 2, - types => new[] - { - typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], types[1]) - }); + types => new[] { typeof(IOrderedEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], types[1]) }); Union = GetMethod( nameof(Enumerable.Union), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(IEnumerable<>).MakeGenericType(types[0]) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(IEnumerable<>).MakeGenericType(types[0]) }); Where = GetMethod( nameof(Enumerable.Where), 1, - types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) - }); + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], typeof(bool)) }); var numericTypes = new[] { - typeof(int), - typeof(int?), - typeof(long), - typeof(long?), - typeof(float), - typeof(float?), - typeof(double), - typeof(double?), - typeof(decimal), - typeof(decimal?) - }; - - AverageWithoutSelectorMethods = new Dictionary(); + typeof(int), + typeof(int?), + typeof(long), + typeof(long?), + typeof(float), + typeof(float?), + typeof(double), + typeof(double?), + typeof(decimal), + typeof(decimal?) + }; + + // AverageWithoutSelectorMethods = new Dictionary(); AverageWithSelectorMethods = new Dictionary(); MaxWithoutSelectorMethods = new Dictionary(); MaxWithSelectorMethods = new Dictionary(); MinWithoutSelectorMethods = new Dictionary(); MinWithSelectorMethods = new Dictionary(); - SumWithoutSelectorMethods = new Dictionary(); + // SumWithoutSelectorMethods = new Dictionary(); SumWithSelectorMethods = new Dictionary(); foreach (var type in numericTypes) { - AverageWithoutSelectorMethods[type] = GetMethod( - nameof(Enumerable.Average), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + // AverageWithoutSelectorMethods[type] = GetMethod( + // nameof(Enumerable.Average), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); AverageWithSelectorMethods[type] = GetMethod( - nameof(Enumerable.Average), 1, types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], type) - }); + nameof(Enumerable.Average), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], type) }); MaxWithoutSelectorMethods[type] = GetMethod( - nameof(Enumerable.Max), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + nameof(Enumerable.Max), 0, _ => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); MaxWithSelectorMethods[type] = GetMethod( - nameof(Enumerable.Max), 1, types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], type) - }); + nameof(Enumerable.Max), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], type) }); MinWithoutSelectorMethods[type] = GetMethod( - nameof(Enumerable.Min), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + nameof(Enumerable.Min), 0, _ => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); MinWithSelectorMethods[type] = GetMethod( - nameof(Enumerable.Min), 1, types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], type) - }); - SumWithoutSelectorMethods[type] = GetMethod( - nameof(Enumerable.Sum), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); + nameof(Enumerable.Min), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], type) }); + // SumWithoutSelectorMethods[type] = GetMethod( + // nameof(Enumerable.Sum), 0, types => new[] { typeof(IEnumerable<>).MakeGenericType(type) }); SumWithSelectorMethods[type] = GetMethod( - nameof(Enumerable.Sum), 1, types => new[] - { - typeof(IEnumerable<>).MakeGenericType(types[0]), - typeof(Func<,>).MakeGenericType(types[0], type) - }); + nameof(Enumerable.Sum), 1, + types => new[] { typeof(IEnumerable<>).MakeGenericType(types[0]), typeof(Func<,>).MakeGenericType(types[0], type) }); } MethodInfo GetMethod(string name, int genericParameterCount, Func parameterGenerator) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/SharedTypeExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/SharedTypeExtensions.cs index c4dd3df94..234f8f9a8 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/SharedTypeExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/SharedTypeExtensions.cs @@ -1,23 +1,24 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using System.Collections.Generic; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; -#nullable enable - // ReSharper disable once CheckNamespace namespace System; [DebuggerStepThrough] internal static class SharedTypeExtensions { - private static readonly Dictionary _builtInTypeNames = new() + private static readonly Dictionary BuiltInTypeNames = new() { { typeof(bool), "bool" }, { typeof(byte), "byte" }, @@ -50,7 +51,7 @@ public static bool IsValidEntityType(this Type type) => type.IsClass && !type.IsArray; - public static bool IsPropertyBagType(this Type type) + public static bool IsPropertyBagType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type) { if (type.IsGenericTypeDefinition) { @@ -106,34 +107,10 @@ public static bool IsAnonymousType(this Type type) && type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), inherit: false).Length > 0 && type.Name.Contains("AnonymousType"); - public static bool IsTupleType(this Type type) - { - if (type == typeof(Tuple)) - { - return true; - } - - if (type.IsGenericType) - { - var genericDefinition = type.GetGenericTypeDefinition(); - if (genericDefinition == typeof(Tuple<>) - || genericDefinition == typeof(Tuple<,>) - || genericDefinition == typeof(Tuple<,,>) - || genericDefinition == typeof(Tuple<,,,>) - || genericDefinition == typeof(Tuple<,,,,>) - || genericDefinition == typeof(Tuple<,,,,,>) - || genericDefinition == typeof(Tuple<,,,,,,>) - || genericDefinition == typeof(Tuple<,,,,,,,>) - || genericDefinition == typeof(Tuple<,,,,,,,>)) - { - return true; - } - } - - return false; - } - - public static PropertyInfo? GetAnyProperty(this Type type, string name) + public static PropertyInfo? GetAnyProperty( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)] + this Type type, + string name) { var props = type.GetRuntimeProperties().Where(p => p.Name == name).ToList(); if (props.Count > 1) @@ -144,51 +121,6 @@ public static bool IsTupleType(this Type type) return props.SingleOrDefault(); } - public static MethodInfo GetRequiredMethod(this Type type, string name, params Type[] parameters) - { - var method = type.GetTypeInfo().GetMethod(name, parameters); - - if (method == null - && parameters.Length == 0) - { - method = type.GetMethod(name); - } - - if (method == null) - { - throw new InvalidOperationException(); - } - - return method; - } - - public static PropertyInfo GetRequiredProperty(this Type type, string name) - => type.GetTypeInfo().GetProperty(name) - ?? throw new InvalidOperationException($"Could not find property '{name}' on type '{type}'"); - - public static FieldInfo GetRequiredDeclaredField(this Type type, string name) - => type.GetTypeInfo().GetDeclaredField(name) - ?? throw new InvalidOperationException($"Could not find field '{name}' on type '{type}'"); - - public static MethodInfo GetRequiredDeclaredMethod(this Type type, string name) - => type.GetTypeInfo().GetDeclaredMethod(name) - ?? throw new InvalidOperationException($"Could not find method '{name}' on type '{type}'"); - - public static MethodInfo GetRequiredDeclaredMethod(this Type type, string name, Func methodSelector) - => type.GetTypeInfo().GetDeclaredMethods(name).Single(methodSelector); - - public static PropertyInfo GetRequiredDeclaredProperty(this Type type, string name) - => type.GetTypeInfo().GetDeclaredProperty(name) - ?? throw new InvalidOperationException($"Could not find property '{name}' on type '{type}'"); - - public static MethodInfo GetRequiredRuntimeMethod(this Type type, string name, params Type[] parameters) - => type.GetTypeInfo().GetRuntimeMethod(name, parameters) - ?? throw new InvalidOperationException($"Could not find method '{name}' on type '{type}'"); - - public static PropertyInfo GetRequiredRuntimeProperty(this Type type, string name) - => type.GetTypeInfo().GetRuntimeProperty(name) - ?? throw new InvalidOperationException($"Could not find property '{name}' on type '{type}'"); - public static bool IsInstantiable(this Type type) => !type.IsAbstract && !type.IsInterface @@ -207,7 +139,7 @@ public static Type UnwrapEnumType(this Type type) return isNullable ? MakeNullable(underlyingEnumType) : underlyingEnumType; } - public static Type GetSequenceType(this Type type) + public static Type GetSequenceType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type) { var sequenceType = TryGetSequenceType(type); if (sequenceType == null) @@ -218,11 +150,13 @@ public static Type GetSequenceType(this Type type) return sequenceType; } - public static Type? TryGetSequenceType(this Type type) + public static Type? TryGetSequenceType([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type) => type.TryGetElementType(typeof(IEnumerable<>)) ?? type.TryGetElementType(typeof(IAsyncEnumerable<>)); - public static Type? TryGetElementType(this Type type, Type interfaceOrBaseType) + public static Type? TryGetElementType( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type, + Type interfaceOrBaseType) { if (type.IsGenericTypeDefinition) { @@ -352,7 +286,8 @@ public static IEnumerable GetTypesInHierarchy(this Type type) } } - public static IEnumerable GetDeclaredInterfaces(this Type type) + public static IEnumerable GetDeclaredInterfaces( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] this Type type) { var interfaces = type.GetInterfaces(); if (type.BaseType == typeof(object) @@ -361,10 +296,18 @@ public static IEnumerable GetDeclaredInterfaces(this Type type) return interfaces; } - return interfaces.Except(type.BaseType.GetInterfaces()); + return interfaces.Except(GetInterfacesSuppressed(type.BaseType)); + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070", Justification = "https://github.com/dotnet/linker/issues/2473")] + static IEnumerable GetInterfacesSuppressed(Type type) + => type.GetInterfaces(); } - public static ConstructorInfo GetDeclaredConstructor(this Type type, Type[]? types) + public static ConstructorInfo? GetDeclaredConstructor( + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] + this Type type, + Type[]? types) { types ??= Array.Empty(); @@ -417,13 +360,20 @@ public static IEnumerable GetMembersInHierarchy(this Type type) while (currentType != null); } - public static IEnumerable GetMembersInHierarchy(this Type type, string name) + public static IEnumerable GetMembersInHierarchy( + [DynamicallyAccessedMembers( + DynamicallyAccessedMemberTypes.PublicProperties + | DynamicallyAccessedMemberTypes.NonPublicProperties + | DynamicallyAccessedMemberTypes.PublicFields + | DynamicallyAccessedMemberTypes.NonPublicFields)] + this Type type, + string name) => type.GetMembersInHierarchy().Where(m => m.Name == name); - private static readonly Dictionary _commonTypeDictionary = new() + private static readonly Dictionary CommonTypeDictionary = new() { #pragma warning disable IDE0034 // Simplify 'default' expression - default causes default(object) - { typeof(int), default(int) }, + { typeof(int), default(int) }, { typeof(Guid), default(Guid) }, { typeof(DateOnly), default(DateOnly) }, { typeof(DateTime), default(DateTime) }, @@ -441,9 +391,10 @@ public static IEnumerable GetMembersInHierarchy(this Type type, stri { typeof(ulong), default(ulong) }, { typeof(sbyte), default(sbyte) } #pragma warning restore IDE0034 // Simplify 'default' expression - }; + }; - public static object? GetDefaultValue(this Type type) + public static object? GetDefaultValue( + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] this Type type) { if (!type.IsValueType) { @@ -453,16 +404,18 @@ public static IEnumerable GetMembersInHierarchy(this Type type, stri // A bit of perf code to avoid calling Activator.CreateInstance for common types and // to avoid boxing on every call. This is about 50% faster than just calling CreateInstance // for all value types. - return _commonTypeDictionary.TryGetValue(type, out var value) + return CommonTypeDictionary.TryGetValue(type, out var value) ? value : Activator.CreateInstance(type); } + [RequiresUnreferencedCode("Gets all types from the given assembly - unsafe for trimming")] public static IEnumerable GetConstructibleTypes(this Assembly assembly) => assembly.GetLoadableDefinedTypes().Where( t => !t.IsAbstract && !t.IsGenericTypeDefinition); + [RequiresUnreferencedCode("Gets all types from the given assembly - unsafe for trimming")] public static IEnumerable GetLoadableDefinedTypes(this Assembly assembly) { try @@ -475,17 +428,6 @@ public static IEnumerable GetLoadableDefinedTypes(this Assembly assemb } } - public static bool IsQueryableType(this Type type) - { - if (type.IsGenericType - && type.GetGenericTypeDefinition() == typeof(IQueryable<>)) - { - return true; - } - - return type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IQueryable<>)); - } - /// /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to /// the same compatibility standards as public APIs. It may be changed or removed without notice in @@ -510,7 +452,7 @@ private static void ProcessType(StringBuilder builder, Type type, bool fullName, { ProcessArrayType(builder, type, fullName, compilable); } - else if (_builtInTypeNames.TryGetValue(type, out var builtInName)) + else if (BuiltInTypeNames.TryGetValue(type, out var builtInName)) { builder.Append(builtInName); } @@ -634,8 +576,18 @@ private static void ProcessGenericType( public static IEnumerable GetNamespaces(this Type type) { - if (_builtInTypeNames.ContainsKey(type)) + if (BuiltInTypeNames.ContainsKey(type)) + { + yield break; + } + + if (type.IsArray) { + foreach (var ns in type.GetElementType()!.GetNamespaces()) + { + yield return ns; + } + yield break; } @@ -654,10 +606,10 @@ public static IEnumerable GetNamespaces(this Type type) } public static ConstantExpression GetDefaultValueConstant(this Type type) - => (ConstantExpression)_generateDefaultValueConstantMethod + => (ConstantExpression)GenerateDefaultValueConstantMethod .MakeGenericMethod(type).Invoke(null, Array.Empty())!; - private static readonly MethodInfo _generateDefaultValueConstantMethod = + private static readonly MethodInfo GenerateDefaultValueConstantMethod = typeof(SharedTypeExtensions).GetTypeInfo().GetDeclaredMethod(nameof(GenerateDefaultValueConstant))!; private static ConstantExpression GenerateDefaultValueConstant() diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/StringBuilderExtensions.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/StringBuilderExtensions.cs index 8a86b6cbb..44bc6c70f 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/StringBuilderExtensions.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Utilities/StringBuilderExtensions.cs @@ -1,11 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +#nullable enable + using System.Collections.Generic; using System.Globalization; -#nullable enable - namespace System.Text; internal static class StringBuilderExtensions diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceHiLoValueGenerator.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceHiLoValueGenerator.cs new file mode 100644 index 000000000..672fe303c --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceHiLoValueGenerator.cs @@ -0,0 +1,81 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using System.Globalization; +using System.Threading; +using System.Threading.Tasks; +using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; +using FirebirdSql.EntityFrameworkCore.Firebird.Update.Internal; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public class FbSequenceHiLoValueGenerator : HiLoValueGenerator +{ + readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; + readonly IFbUpdateSqlGenerator _sqlGenerator; + readonly IFbRelationalConnection _connection; + readonly ISequence _sequence; + readonly IRelationalCommandDiagnosticsLogger _commandLogger; + + public FbSequenceHiLoValueGenerator(IRawSqlCommandBuilder rawSqlCommandBuilder, IFbUpdateSqlGenerator sqlGenerator, FbSequenceValueGeneratorState generatorState, IFbRelationalConnection connection, IRelationalCommandDiagnosticsLogger commandLogger) + : base(generatorState) + { + _sequence = generatorState.Sequence; + _rawSqlCommandBuilder = rawSqlCommandBuilder; + _sqlGenerator = sqlGenerator; + _connection = connection; + _commandLogger = commandLogger; + } + + protected override long GetNewLowValue() + => (long)Convert.ChangeType( + _rawSqlCommandBuilder + .Build(_sqlGenerator.GenerateNextSequenceValueOperation(_sequence.Name, _sequence.Schema)) + .ExecuteScalar( + new RelationalCommandParameterObject( + _connection, + parameterValues: null, + readerColumns: null, + context: null, + _commandLogger, CommandSource.ValueGenerator)), + typeof(long), + CultureInfo.InvariantCulture)!; + + protected override async Task GetNewLowValueAsync(CancellationToken cancellationToken = default) + => (long)Convert.ChangeType( + await _rawSqlCommandBuilder + .Build(_sqlGenerator.GenerateNextSequenceValueOperation(_sequence.Name, _sequence.Schema)) + .ExecuteScalarAsync( + new RelationalCommandParameterObject( + _connection, + parameterValues: null, + readerColumns: null, + context: null, + _commandLogger, CommandSource.ValueGenerator), + cancellationToken) + .ConfigureAwait(false), + typeof(long), + CultureInfo.InvariantCulture)!; + + public override bool GeneratesTemporaryValues + => false; +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorFactory.cs new file mode 100644 index 000000000..628096146 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorFactory.cs @@ -0,0 +1,91 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; +using FirebirdSql.EntityFrameworkCore.Firebird.Update.Internal; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public class FbSequenceValueGeneratorFactory : IFbSequenceValueGeneratorFactory +{ + readonly IFbUpdateSqlGenerator _sqlGenerator; + + public FbSequenceValueGeneratorFactory(IFbUpdateSqlGenerator sqlGenerator) + { + _sqlGenerator = sqlGenerator; + } + + public virtual ValueGenerator TryCreate(IProperty property, Type type, FbSequenceValueGeneratorState generatorState, IFbRelationalConnection connection, IRawSqlCommandBuilder rawSqlCommandBuilder, IRelationalCommandDiagnosticsLogger commandLogger) + { + if (type == typeof(long)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(int)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(decimal)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(short)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(byte)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(char)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(ulong)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(uint)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(ushort)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + if (type == typeof(sbyte)) + { + return new FbSequenceHiLoValueGenerator(rawSqlCommandBuilder, _sqlGenerator, generatorState, connection, commandLogger); + } + + return null; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorState.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorState.cs new file mode 100644 index 000000000..b4e96b770 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbSequenceValueGeneratorState.cs @@ -0,0 +1,32 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public class FbSequenceValueGeneratorState : HiLoValueGeneratorState +{ + public FbSequenceValueGeneratorState(ISequence sequence) + : base(sequence.IncrementBy) + { + Sequence = sequence; + } + + public virtual ISequence Sequence { get; } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs new file mode 100644 index 000000000..1eb45a3a5 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorCache.cs @@ -0,0 +1,57 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System.Collections.Concurrent; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public class FbValueGeneratorCache : ValueGeneratorCache, IFbValueGeneratorCache +{ + readonly ConcurrentDictionary _sequenceGeneratorCache = new ConcurrentDictionary(); + + public FbValueGeneratorCache(ValueGeneratorCacheDependencies dependencies) + : base(dependencies) + { } + + public virtual FbSequenceValueGeneratorState GetOrAddSequenceState(IProperty property, IRelationalConnection connection) + { + var tableIdentifier = StoreObjectIdentifier.Create(property.DeclaringEntityType, StoreObjectType.Table); + var sequence = tableIdentifier != null + ? property.FindHiLoSequence(tableIdentifier.Value) + : property.FindHiLoSequence(); + + return _sequenceGeneratorCache.GetOrAdd( + GetSequenceName(sequence, connection), + _ => new FbSequenceValueGeneratorState(sequence)); + } + + static string GetSequenceName(ISequence sequence, IRelationalConnection connection) + { + var dbConnection = connection.DbConnection; + + return dbConnection.Database.ToUpperInvariant() + + "::" + + dbConnection.DataSource.ToUpperInvariant() + + "::" + + (sequence.Schema == null ? "" : sequence.Schema + ".") + + sequence.Name; + } +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs new file mode 100644 index 000000000..7f80548f4 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/FbValueGeneratorSelector.cs @@ -0,0 +1,99 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using FirebirdSql.EntityFrameworkCore.Firebird.Metadata; +using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public class FbValueGeneratorSelector : RelationalValueGeneratorSelector +{ + readonly IFbSequenceValueGeneratorFactory _sequenceFactory; + readonly IFbRelationalConnection _connection; + readonly IRawSqlCommandBuilder _rawSqlCommandBuilder; + readonly IRelationalCommandDiagnosticsLogger _commandLogger; + + public FbValueGeneratorSelector(ValueGeneratorSelectorDependencies dependencies, IFbSequenceValueGeneratorFactory sequenceFactory, IFbRelationalConnection connection, IRawSqlCommandBuilder rawSqlCommandBuilder, IRelationalCommandDiagnosticsLogger commandLogger) + : base(dependencies) + { + _sequenceFactory = sequenceFactory; + _connection = connection; + _rawSqlCommandBuilder = rawSqlCommandBuilder; + _commandLogger = commandLogger; + } + + public new virtual IFbValueGeneratorCache Cache => (IFbValueGeneratorCache)base.Cache; + + public override ValueGenerator Select(IProperty property, IEntityType entityType) + { + if (property.GetValueGeneratorFactory() != null + || property.GetValueGenerationStrategy() != FbValueGenerationStrategy.HiLo) + { + return base.Select(property, entityType); + } + + var propertyType = property.ClrType.UnwrapNullableType().UnwrapEnumType(); + + var generator = _sequenceFactory.TryCreate( + property, + propertyType, + Cache.GetOrAddSequenceState(property, _connection), + _connection, + _rawSqlCommandBuilder, + _commandLogger); + + if (generator != null) + { + return generator; + } + + var converter = property.GetTypeMapping().Converter; + if (converter != null + && converter.ProviderClrType != propertyType) + { + generator = _sequenceFactory.TryCreate( + property, + converter.ProviderClrType, + Cache.GetOrAddSequenceState(property, _connection), + _connection, + _rawSqlCommandBuilder, + _commandLogger); + + if (generator != null) + { + return generator.WithConverter(converter); + } + } + + throw new ArgumentException( + CoreStrings.InvalidValueGeneratorFactoryProperty( + nameof(FbSequenceValueGeneratorFactory), property.Name, property.DeclaringEntityType.DisplayName())); + } + + protected override ValueGenerator FindForType(IProperty property, IEntityType entityType, Type clrType) + => property.ClrType.UnwrapNullableType() == typeof(Guid) + ? property.ValueGenerated == ValueGenerated.Never || property.GetDefaultValueSql() != null + ? new TemporaryGuidValueGenerator() + : new SequentialGuidValueGenerator() + : base.FindForType(property, entityType, clrType); +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbSequenceValueGeneratorFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbSequenceValueGeneratorFactory.cs new file mode 100644 index 000000000..719207419 --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbSequenceValueGeneratorFactory.cs @@ -0,0 +1,30 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using System; +using FirebirdSql.EntityFrameworkCore.Firebird.Storage.Internal; +using Microsoft.EntityFrameworkCore.Diagnostics; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public interface IFbSequenceValueGeneratorFactory +{ + ValueGenerator TryCreate(IProperty property, Type clrType, FbSequenceValueGeneratorState generatorState, IFbRelationalConnection connection, IRawSqlCommandBuilder rawSqlCommandBuilder, IRelationalCommandDiagnosticsLogger commandLogger); +} diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbValueGeneratorCache.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbValueGeneratorCache.cs new file mode 100644 index 000000000..3cc26246a --- /dev/null +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/ValueGeneration/Internal/IFbValueGeneratorCache.cs @@ -0,0 +1,27 @@ +/* + * The contents of this file are subject to the Initial + * Developer's Public License Version 1.0 (the "License"); + * you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * https://github.com/FirebirdSQL/NETProvider/raw/master/license.txt. + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * All Rights Reserved. + */ + +//$Authors = Jiri Cincura (jiri@cincura.net) + +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.ValueGeneration; + +namespace FirebirdSql.EntityFrameworkCore.Firebird.ValueGeneration.Internal; + +public interface IFbValueGeneratorCache : IValueGeneratorCache +{ + FbSequenceValueGeneratorState GetOrAddSequenceState(IProperty property, IRelationalConnection connection); +} diff --git a/src/Perf/Perf.csproj b/src/Perf/Perf.csproj index 7efab90cc..4f300758b 100644 --- a/src/Perf/Perf.csproj +++ b/src/Perf/Perf.csproj @@ -1,7 +1,7 @@  Exe - net6.0 + net7.0 true diff --git a/src/Scratchpad/Program.cs b/src/Scratchpad/Program.cs index 50676928c..c86ad4fbe 100644 --- a/src/Scratchpad/Program.cs +++ b/src/Scratchpad/Program.cs @@ -23,4 +23,4 @@ static void Main(string[] args) { // Scratchpad } -} \ No newline at end of file +} diff --git a/src/Scratchpad/Scratchpad.csproj b/src/Scratchpad/Scratchpad.csproj index 12c71a531..03f5f17c9 100644 --- a/src/Scratchpad/Scratchpad.csproj +++ b/src/Scratchpad/Scratchpad.csproj @@ -1,7 +1,7 @@  Exe - net6.0 + net7.0 true true ..\FirebirdSql.Data.TestsBase\FirebirdSql.Data.TestsBase.snk