The Provider could not be resolved. You must explicitly set the Provider.
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
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
CustomDbConnectionthat will allow you to specify the currentInnerConnection(Oracle or SQL Server in your case). It will not use yourDatabaseConnectionAdapterbut at least, it will work. You will only need to set this option once. - You specify the
InnerConnectionin theConnectionproperty every time you useBulkSaveChangesor 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 yourDatabaseConnectionAdapterbut 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
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..
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
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]
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