From c44302e45c45fccbef5a81d3474eba615d85c30c Mon Sep 17 00:00:00 2001 From: Omar Date: Sun, 15 Feb 2026 19:44:23 +0000 Subject: [PATCH] feat: to ef-core-10 --- .gitignore | 3 +++ .vscode/tasks.json | 15 ++++++++----- Directory.Packages.props | 21 +++++++------------ global.json | 2 +- .../Internal/MySqlQuerySqlGenerator.cs | 18 ++++++++++++++++ .../Query/EscapesMySqlTestBase.cs | 6 ++++-- .../Query/GearsOfWarQueryMySqlTest.cs | 4 +++- .../Query/TPCGearsOfWarQueryMySqlTest.cs | 4 +++- .../Query/TPTGearsOfWarQueryMySqlTest.cs | 4 +++- test/EFCore.MySql.FunctionalTests/README.md | 2 ++ test/EFCore.MySql.IntegrationTests/README.md | 2 ++ 11 files changed, 57 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index 1ceed1dc6..63be1f19e 100644 --- a/.gitignore +++ b/.gitignore @@ -338,3 +338,6 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ + +#VSCode +.vscode/ diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 476b30e9f..ad071dfb6 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,16 +1,21 @@ { - "version": "0.1.0", + "version": "2.0.0", "command": "dotnet", - "isShellCommand": true, "args": [], "tasks": [ { - "taskName": "build", + "label": "build", + "type": "shell", + "command": "dotnet", "args": [ + "build", "${workspaceRoot}/test/EFCore.MySql.IntegrationTests/EFCore.MySql.IntegrationTests.csproj" ], - "isBuildCommand": true, - "problemMatcher": "$msCompile" + "problemMatcher": "$msCompile", + "group": { + "_id": "build", + "isDefault": false + } } ] } \ No newline at end of file diff --git a/Directory.Packages.props b/Directory.Packages.props index c4e17801f..84844f410 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,19 +5,15 @@ --> [9.0.0,9.0.999] - - + - - + - - - - + + @@ -28,19 +24,19 @@ - - + + + - + - @@ -48,7 +44,6 @@ - diff --git a/global.json b/global.json index db8627a23..2793da572 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.100", + "version": "10.0.103", "allowPrerelease": false, "rollForward": "latestFeature" } diff --git a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs index c86ad0e9e..610d61804 100644 --- a/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs +++ b/src/EFCore.MySql/Query/ExpressionVisitors/Internal/MySqlQuerySqlGenerator.cs @@ -249,6 +249,14 @@ protected override void GenerateLimitOffset(SelectExpression selectExpression) } } + // Single-argument aggregates: generate Name(arg) to match historical SQL shape. + // EF Core 9.x base now generates Name((arg)); we keep the old format for backward compatibility. + private static readonly HashSet SingleArgAggregateFunctions = new(StringComparer.OrdinalIgnoreCase) + { + "AVG", "MAX", "MIN", "SUM", "COUNT", "BIT_AND", "BIT_OR", "BIT_XOR", + "STD", "STDDEV", "STDDEV_POP", "STDDEV_SAMP", "VAR_POP", "VAR_SAMP", "VARIANCE", + }; + protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression) { if (sqlFunctionExpression.Name.StartsWith("@@", StringComparison.Ordinal)) @@ -258,6 +266,16 @@ protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunction return sqlFunctionExpression; } + if (SingleArgAggregateFunctions.Contains(sqlFunctionExpression.Name) + && sqlFunctionExpression.Arguments.Count == 1) + { + Sql.Append(sqlFunctionExpression.Name); + Sql.Append("("); + Visit(sqlFunctionExpression.Arguments[0]); + Sql.Append(")"); + return sqlFunctionExpression; + } + return base.VisitSqlFunction(sqlFunctionExpression); } diff --git a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs index ac08eae8d..d6698fcac 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/EscapesMySqlTestBase.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -84,7 +84,9 @@ public virtual async Task Where_contains_query_escapes(bool async) { using (var context = CreateContext()) { - var artistNames = new[] + // Use List so Contains binds to Enumerable.Contains; array can bind to + // MemoryExtensions.Contains(ReadOnlySpan) and break the expression interpreter. + var artistNames = new List { @"Back\slasher's", @"John's Chill Box" diff --git a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs index 081add88c..dcdd0b4ef 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/GearsOfWarQueryMySqlTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -26,7 +27,8 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); var start = dto.AddDays(-1); var end = dto.AddDays(1); - var dates = new[] { dto }; + // Use List to avoid ReadOnlySpan in expression tree (same as EscapesMySqlTestBase). + var dates = new List { dto }; return AssertQuery( async, diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs index e94bd2631..b29a2880e 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/TPCGearsOfWarQueryMySqlTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -9147,7 +9148,8 @@ public override async Task DateTimeOffset_Contains_Less_than_Greater_than(bool a var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); var start = dto.AddDays(-1); var end = dto.AddDays(1); - var dates = new[] { dto }; + // Use List to avoid ReadOnlySpan in expression tree (same as GearsOfWarQueryMySqlTest). + var dates = new List { dto }; await AssertQuery( async, diff --git a/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs b/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs index a0a91e103..75f8e3abf 100644 --- a/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs +++ b/test/EFCore.MySql.FunctionalTests/Query/TPTGearsOfWarQueryMySqlTest.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Threading.Tasks; @@ -28,7 +29,8 @@ public override Task DateTimeOffset_Contains_Less_than_Greater_than(bool async) var dto = MySqlTestHelpers.GetExpectedValue(new DateTimeOffset(599898024001234567, new TimeSpan(1, 30, 0))); var start = dto.AddDays(-1); var end = dto.AddDays(1); - var dates = new[] { dto }; + // Use List to avoid ReadOnlySpan in expression tree (same as GearsOfWarQueryMySqlTest). + var dates = new List { dto }; return AssertQuery( async, diff --git a/test/EFCore.MySql.FunctionalTests/README.md b/test/EFCore.MySql.FunctionalTests/README.md index b50af38b1..813b87d56 100644 --- a/test/EFCore.MySql.FunctionalTests/README.md +++ b/test/EFCore.MySql.FunctionalTests/README.md @@ -3,6 +3,8 @@ Functional Tests **Configuring the Database** +The functional tests are intended to be run against **MySQL 8.0+** or an equivalent **MariaDB** version (see the main README for tested versions). + Configure your MySQL database by opening the `config.json.example` file, specifying the connection string and saving the changed file as `config.json`. **Running Functional Tests** diff --git a/test/EFCore.MySql.IntegrationTests/README.md b/test/EFCore.MySql.IntegrationTests/README.md index bd67efbc4..194f58e97 100644 --- a/test/EFCore.MySql.IntegrationTests/README.md +++ b/test/EFCore.MySql.IntegrationTests/README.md @@ -3,6 +3,8 @@ Integration and Performance Tests **Configuring the Database** +The integration tests are intended to be run against **MySQL 8.0+** or an equivalent **MariaDB** version (see the main README for tested versions). + 1. Configure your MySQL database by opening the `config.json.example` file, specifying the connection string and saving the changed file as `config.json`. 2. Run the `scripts/rebuild.ps1` PowerShell script on Linux or Windows to rebuild all migrations (for installing PowerShell, see [Install PowerShell on Windows, Linux, and macOS](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell)). Any time you make changes to the database models, run the rebuild script again.