EFCore.BulkExtensions icon indicating copy to clipboard operation
EFCore.BulkExtensions copied to clipboard

Not able to use the package with .NET 9

Open Thovenaar opened this issue 1 year ago • 22 comments

The following error comes up when you upgrade to .NET 9.

Warning As Error: Detected package version outside of dependency constraint: Pomelo.EntityFrameworkCore.MySql 8.0.2 requires Microsoft.EntityFrameworkCore.Relational (>= 8.0.2 && <= 8.0.999) but version Microsoft.EntityFrameworkCore.Relational 9.0.0 was resolved.

I think we need to either upgrade Pomelo.EntityFrameworkCore to support .NET 9 or find a replacement.

Thovenaar avatar Nov 14 '24 20:11 Thovenaar

This is specifically for the MySql package which I am not using at the moment. I decided to install just the SqlServer package and that worked for me. Closing this issue.

Thovenaar avatar Nov 15 '24 10:11 Thovenaar

Will check it out for MY as well, soon when new version gets added.

borisdj avatar Nov 15 '24 12:11 borisdj

I didn't have success with PGSQL either. I will re-check it in the coming days.

benpsnyder avatar Nov 19 '24 17:11 benpsnyder

I will reopen the issue as the actual problem is still not solved due to an external dependency.

Thovenaar avatar Nov 19 '24 19:11 Thovenaar

Pomelo for MySql has preRelease 9 but even that has some companitibilty issues. Still they said that Release version would be published this or next week, so will update it to 9 as soon as they publish it. If it does not get published till the end of November will then try to publish prerelease of Bulk 9 as well.

borisdj avatar Nov 21 '24 00:11 borisdj

v9.0.0-rc.1 is now published on nuget. Will be updated to full release as soon as Mysql v9 is also fully release, expecting it to be in a few days.

borisdj avatar Dec 01 '24 23:12 borisdj

I have installed the preview version and tried it. Getting the same error that I mentioned in #1620

packages

at EFCore.BulkExtensions.IQueryableExtensions.ToParametrizedSql(IQueryable query) at EFCore.BulkExtensions.BatchUtil.GetBatchSql(IQueryable query, DbContext context, Boolean isUpdate) at EFCore.BulkExtensions.SqlAdapters.SqlQueryBuilder.MergeTable[T](DbContext context, TableInfo tableInfo, OperationType operationType, IEnumerable1 entityPropertyWithDefaultValue) at EFCore.BulkExtensions.SqlAdapters.SqlServer.SqlServerAdapter.<MergeAsync>d__91.MoveNext() at EFCore.BulkExtensions.SqlAdapters.SqlServer.SqlServerAdapter.<MergeAsync>d__91.MoveNext() at EFCore.BulkExtensions.SqlAdapters.SqlServer.SqlServerAdapter.<MergeAsync>d__81.MoveNext() at EFCore.BulkExtensions.SqlBulkOperation.<MergeAsync>d__51.MoveNext() at EFCore.BulkExtensions.DbContextBulkTransaction.<ExecuteAsync>d__11.MoveNext()

evicio1 avatar Dec 02 '24 14:12 evicio1

@evicio1 are you using one of configs SynchronizeFilter or SynchronizeSoftDelete ?

borisdj avatar Dec 02 '24 15:12 borisdj

Yes, SynchronizeFilter.

ex:

await context.BulkInsertOrUpdateOrDeleteAsync(dto, options =>
            {
                options.UpdateByProperties = ["Code"];
                options.PropertiesToExcludeOnUpdate = [
                    "Percentage","Description","CountryCode",];
                options.SetSynchronizeFilter<MonthlySalary>(x => x.code == "TEST");
            }, cancellationToken: cancellationToken);
            

evicio1 avatar Dec 02 '24 17:12 evicio1

@evicio1 Can you write entire test for this (or alter existing one for BulkSync), not able to repreduce it. Still I can see where the bug is but don't have the sollution at the moment.

borisdj avatar Dec 02 '24 22:12 borisdj

This is specifically for the MySql package which I am not using at the moment. I decided to install just the SqlServer package and that worked for me. Closing this issue.

We're not using any MySql packages but I am not able to update Microsoft.EntityFrameworkCore.SqlServer package to 9.0.0 because of the following error: EFCore.BulkExtensions 8.1.2 -> EFCore.BulkExtensions.MySql 8.1.2 -> Pomelo.EntityFrameworkCore.MySql 8.0.2 -> Microsoft.EntityFrameworkCore.Relational (>= 8.0.2 && <= 8.0.999).

These are our relevant nuget packages: EFCore.BulkExtensions v8.1.2 Microsoft.EntityFrameworkCore v8.0.11 Microsoft.EntityFrameworkCore.SqlServer v8.0.11

smolleman avatar Dec 03 '24 10:12 smolleman

@borisdj It seems the issue lies with IQueryableExtensions.ToParametrizedSql(). In EF Core 9, it appears that retrieving RelationalCommandCache using the following approach is no longer working: var relationalCommandCache = (RelationalCommandCache?)enumerator.Private(relationalCommandCacheText);

I implemented a small fix that seems to resolve the issue. Could you please review it?

 string relationalCommandResolverText = "_relationalCommandResolver";
var relationalCommandResolver = enumerator.Private<Delegate>(relationalCommandResolverText);
command = (IRelationalCommand)relationalCommandResolver.DynamicInvoke(parameterValues);

public static class IQueryableExtensions
{
    /// <summary>
    /// Extension method to paramatize sql query
    /// </summary>
    /// <param name="query"></param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public static (string, IEnumerable<DbParameter>) ToParametrizedSql(this IQueryable query)
    {
        string relationalQueryContextText = "_relationalQueryContext";
        string relationalCommandCacheText = "_relationalCommandCache";
        string relationalCommandResolverText = "_relationalCommandResolver";
        

        string cannotGetText = "Cannot get";

#pragma warning disable CS8602 // Dereference of a possibly null reference.
        var enumerator = query.Provider.Execute<IEnumerable>(query.Expression).GetEnumerator();
#pragma warning restore CS8602 // Dereference of a possibly null reference.
        var queryContext = enumerator.Private<RelationalQueryContext>(relationalQueryContextText) ?? throw new InvalidOperationException($"{cannotGetText} {relationalQueryContextText}");
        var parameterValues = queryContext.ParameterValues;

#pragma warning disable EF1001 // Internal EF Core API usage.
        var relationalCommandCache = (RelationalCommandCache?)enumerator.Private(relationalCommandCacheText);
        var relationalCommandResolver = enumerator.Private<Delegate>(relationalCommandResolverText);
#pragma warning restore EF1001

        IRelationalCommand command;
        if (relationalCommandResolver != null)
        {
#pragma warning disable EF1001 // Internal EF Core API usage.
            command = (IRelationalCommand)relationalCommandResolver.DynamicInvoke(parameterValues);
            //command = (IRelationalCommand)relationalCommandCache.GetRelationalCommandTemplate(parameterValues);
#pragma warning restore EF1001
        }
        else
        {
            string selectExpressionText = "_selectExpression";
            string querySqlGeneratorFactoryText = "_querySqlGeneratorFactory";
            SelectExpression selectExpression = enumerator.Private<SelectExpression>(selectExpressionText) ?? throw new InvalidOperationException($"{cannotGetText} {selectExpressionText}");
            IQuerySqlGeneratorFactory factory = enumerator.Private<IQuerySqlGeneratorFactory>(querySqlGeneratorFactoryText) ?? throw new InvalidOperationException($"{cannotGetText} {querySqlGeneratorFactoryText}");
            command = factory.Create().GetCommand(selectExpression);
        }
        string sql = command.CommandText;

        IList<DbParameter> parameters;
        try
        {
            using var dbCommand = SqlAdaptersMapping.DbServer.QueryBuilder.CreateCommand(); // Use a DbCommand to convert parameter values using ValueConverters to the correct type.
            foreach (var param in command.Parameters)
            {
                var values = parameterValues[param.InvariantName];
                param.AddDbParameter(dbCommand, values);
            }
            parameters = new List<DbParameter>(dbCommand.Parameters.OfType<DbParameter>());
            dbCommand.Parameters.Clear();
        }
        catch (Exception ex) // Fix for BatchDelete with 'uint' param on Sqlite. TEST: RunBatchUint
        {
            var npgsqlSpecParamMessage = "Npgsql-specific type mapping ";
            // Full Msg:
            // "Npgsql-specific type mapping Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.Mapping.NpgsqlArrayListTypeMapping being used with non-Npgsql parameter type SqlParameter"
            // "Npgsql-specific type mapping NpgsqlTimestampTzTypeMapping being used with non-Npgsql parameter type SqlParameter" // for Batch (a < date)

            if (ex.Message.StartsWith("No mapping exists from DbType") && ex.Message.EndsWith("to a known SqlDbType.") || // example: "No mapping exists from DbType UInt32 to a known SqlDbType."
                ex.Message.StartsWith(npgsqlSpecParamMessage)) // Fix for BatchDelete with Contains on PostgreSQL
            {
                var parameterNames = new HashSet<string>(command.Parameters.Select(p => p.InvariantName));
                parameters = parameterValues.Where(pv => parameterNames.Contains(pv.Key)).Select(pv => SqlAdaptersMapping.DbServer.QueryBuilder.CreateParameter("@" + pv.Key, pv.Value)).ToList();
            }
            else
            {
                throw;
            }
        }
        return (sql, parameters);
    }

evicio1 avatar Dec 03 '24 12:12 evicio1

@evicio1 I have integrate it and made a commit. Can you take the latest source and check that it works for you case.

borisdj avatar Dec 04 '24 21:12 borisdj

Also provider specific nugets for MS, PG and LT are now published in full release 9.0.0. MY is not and also Main, that has all providers, is not since MySql {review version has dependency conflict with Release.

borisdj avatar Dec 04 '24 22:12 borisdj

I have tested and it's all good. Thank you @borisdj

evicio1 avatar Dec 05 '24 05:12 evicio1

When will this fix be available for net core 9.0

Anderman avatar Jan 02 '25 14:01 Anderman

Any update on this at all? Would love to move to EF9 but can't and EF8 is now giving vulnerability issues...

administersoftware avatar Jan 23 '25 12:01 administersoftware

Tested today with 9_rc1. Still the same issue

    Cannot get _selectExpression
IQueryableExtensions.ToParametrizedSql(IQueryable query)
BatchUtil.GetBatchSql(IQueryable query, DbContext context, Boolean isUpdate)
SqlQueryBuilder.MergeTable[T](DbContext context, TableInfo tableInfo, OperationType operationType, IEnumerable`1 entityPropertyWithDefaultValue)
SqlServerAdapter.MergeAsync[T](DbContext context, Type type, IEnumerable`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress, Boolean isAsync, CancellationToken cancellationToken)
SqlServerAdapter.MergeAsync[T](DbContext context, Type type, IEnumerable`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress, Boolean isAsync, CancellationToken cancellationToken)
SqlServerAdapter.MergeAsync[T](DbContext context, Type type, IEnumerable`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress, CancellationToken cancellationToken)
SqlBulkOperation.MergeAsync[T](DbContext context, Type type, IEnumerable`1 entities, TableInfo tableInfo, OperationType operationType, Action`1 progress, CancellationToken cancellationToken)
DbContextBulkTransaction.ExecuteAsync[T](DbContext context, Type type, IEnumerable`1 entities, OperationType operationType, BulkConfig bulkConfig, Action`1 progress, CancellationToken cancellationToken)

Anderman avatar Feb 04 '25 16:02 Anderman

I'm using the RC1 and the only issue I'm getting is build warning as I'm using EF 9.0.1 and not EF 9.0.0, however it does build and run

administersoftware avatar Feb 04 '25 16:02 administersoftware

If I decompile the 9.0.1 version than I still missing the fix public static (string, IEnumerable<DbParameter>) ToParametrizedSql(this IQueryable query) { string relationalQueryContextText = "_relationalQueryContext"; string relationalCommandCacheText = "_relationalCommandCache"; string relationalCommandResolverText = "_relationalCommandResolver";

Image

Anderman avatar Feb 04 '25 16:02 Anderman

New versions with latest source are published v 8.1.3 for EF8 and v 9.0.1 for EF9. Make a test for the issue with these versions.

borisdj avatar Feb 17 '25 23:02 borisdj

Hello, I use EFCore v 9.0.2 and installed EfCore.BulkExtensions v 9.0.1 but in the using statement the namespace could not be found :-( VS version: Microsoft Visual Studio Enterprise 2022 (64-bit) - Current Version 17.12.1

PascalBlom avatar May 21 '25 14:05 PascalBlom