EntityFramework-Extensions icon indicating copy to clipboard operation
EntityFramework-Extensions copied to clipboard

The Provider could not be resolved. You must explicitly set the Provider.

Open sinanakyazici opened this issue 4 years ago • 5 comments

Description

I try to use BulkSaveChanges, but I get an error 'The Provider could not be resolved. You must explicitly set the Provider.' I'm using a databasewrapper like below, It works when I use OracleConnection, but It doesn't work when I use my DatabaseConnectionAdapter . What is wrong with that ?

    public class DatabaseConnectionAdapter : DbConnection
    {
        private readonly IDatabaseConnectionManager owner;

        private readonly DatabaseConfiguration configuration;

        private readonly IUserContextAccessor userContextAccessor;

        private readonly IExecutionContextAccessor executionContextAccessor;

        private readonly int connRetryTimes = 5;

        private readonly TimeSpan connBetweenExceptionWait = TimeSpan.FromSeconds(10);

        private bool disposedValue = false; // To detect redundant calls

        public DatabaseConnectionAdapter(IDatabaseConnectionManager owner, DatabaseConfiguration database,
            IUserContextAccessor userContextAccessor, IExecutionContextAccessor executionContextAccessor)
        {
            this.owner = owner;
            this.configuration = database;
            this.userContextAccessor = userContextAccessor;
            this.executionContextAccessor = executionContextAccessor;
            switch (this.configuration.Type)
            {
                case DatabaseType.SqlServer:
                    this.InnerConnection = new SqlConnection(this.configuration.ConnectionString);
                    this.Open();
                    break;
                case DatabaseType.Oracle:
                    this.InnerConnection = new OracleConnection(this.configuration.ConnectionString);
                    this.Open();
                    break;
                default:
                    throw new NotSupportedException(
                        $"Name:{this.configuration.Name} Type:{this.configuration.Type} is not supported");
            }
        }

        public DbConnection InnerConnection { get; }

        public override string ConnectionString
        {
            get => this.InnerConnection.ConnectionString;
            set => this.InnerConnection.ConnectionString = value;
        }

        public override string Database => this.InnerConnection.Database;

        public override string DataSource => this.InnerConnection.DataSource;

        public override string ServerVersion => this.InnerConnection.ServerVersion;

        public override ConnectionState State => this.InnerConnection.State;

        public override void ChangeDatabase(string databaseName)
        {
            this.InnerConnection.ChangeDatabase(databaseName);
        }

        public override void Close()
        {
            this.InnerConnection.Close();
        }

        public override void Open()
        {
            var connRetryPolicy = Policy.Handle<OracleException>(e => e.Message.ContainsAny("ORA-02396", "ORA-12516"))
                .WaitAndRetry(this.connRetryTimes, i => this.connBetweenExceptionWait);

            connRetryPolicy.Execute(() =>
            {
                if (this.InnerConnection != null && this.State != ConnectionState.Open)
                {
                    this.InnerConnection.Open();

                   // some stuff
                }
            });
        }

        protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
        {
            var transaction = this.InnerConnection.BeginTransaction();
            return new DatabaseTransactionAdapter(this, transaction);
        }

        protected override DbCommand CreateDbCommand()
        {
            try
            {
                return this.InnerConnection.CreateCommand();
            }
            catch (OracleException ex) when (ex.Message.ContainsAny("ORA-02396", "ORA-12516"))
            {
                this.Open();
                return this.InnerConnection.CreateCommand();
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (!this.disposedValue)
            {
                if (disposing)
                {
                    if (this.InnerConnection.State == ConnectionState.Open)
                    {
                        this.InnerConnection.Close();
                    }

                    // TODO: dispose managed state (managed objects).
                    this.InnerConnection.Dispose();
                }

                // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
                // TODO: set large fields to null.
                this.disposedValue = true;
            }
        }

Exception

The Provider could not be resolved. You must explicitly set the Provider.

Exception message:
Stack trace:

at Z.BulkOperations.BulkOperation.()\r\n   
at Z.BulkOperations.BulkOperation.Execute()\r\n   
at Z.BulkOperations.BulkOperation.BulkUpdate()\r\n   
at .BulkUpdate[T](DbContext this, IEntityType entityType, IEnumerable`1 list, Action`1 options, SavingSelector savingSelector, Boolean forceSpecificTypeMapping)\r\n   
at .BulkUpdate[T](DbContext this, IEnumerable`1 entities, Action`1 options, Boolean isBulkSaveChanges)\r\n   
at .(DbContext this, List`1 , Action`1 )\r\n   
at .(DbContext this, StateManager , IReadOnlyList`1 , Action`1 )\r\n   
at .(DbContext this, StateManager , IReadOnlyList`1 , Action`1 )\r\n   
at .(DbContext this, Action`1 , DbContext )\r\n   
at DbContextExtensions.BulkSaveChanges(DbContext this, Action`1 options)\r\n   
at DbContextExtensions.BulkSaveChanges(DbContext this)\r\n  

sinanakyazici avatar Jun 28 '21 09:06 sinanakyazici

Hello @sinanakyazici ,

That issue happens because we are not able to find your OracleConnection from your DatabaseConnectionAdapter connection.

At this moment, we do not support custom Connection.

There are 2 solutions that we can think of:

  • We add a new global option such as CustomDbConnection that will allow you to specify the current InnerConnection (Oracle or SQL Server in your case). It will not use your DatabaseConnectionAdapter but at least, it will work. You will only need to set this option once.
  • You specify the InnerConnection in the Connection property every time you use BulkSaveChanges or any other methods. That current doesn't work but we could make a change in our library to check if the property is set first. Again it will not use your DatabaseConnectionAdapter but at least, it will work. You will only need to set this option once.

Let me know if that could work for you and what's your preference.

Best Regards,

Jon

JonathanMagnan avatar Jun 28 '21 13:06 JonathanMagnan

Thanks Jon,

I think we can use the Z like this way.

var db = (DatabaseConnectionAdapter)this.Context.Database.GetDbConnection();
this.Context.Database.SetDbConnection(db.InnerConnection);
await this.Context.BulkSaveChangesAsync(cancellationToken).ConfigureAwait(false);

We suppose to buy the extensions license as company. I would like to ask another question, Can you support any logging for bulk operations ? Such as before and after state of entity, execution times, audit logs etc..

sinanakyazici avatar Jun 29 '21 09:06 sinanakyazici

Hello @sinanakyazici ,

Partially, but you will have some work to do probably to get exactly what you want:

Auditing: The auditing is done directly from database values (old and new) and not context values. Logging: some information about the execution times, methods, SQL command can be found here.

Let me know if that answer to this last question

JonathanMagnan avatar Jun 29 '21 12:06 JonathanMagnan

Hello @sinanakyazici ,

It is possible for you to provide the code of your DatabaseTransactionAdapter, my developer has some issues making the code work when the DatabaseConnectionAdapter returns a SqlCommand (can do it with a custom command).

He is very interested to know how you did it. If needed, you can send it in private here: [email protected]

JonathanMagnan avatar Jun 29 '21 14:06 JonathanMagnan

Hello @sinanakyazici

Since our last conversation, we haven't heard from you!

don't hesitate to contact us with any questions or further assistance.

Best regards,

Jon

JonathanMagnan avatar Jul 06 '21 12:07 JonathanMagnan