I'm working on a project using ASP.NET Core 2.1 and EF Core 2.1. Although most of queries and commands use EF, some units needs to call stored procedures directly.
I can't use FromSql
, because it needs results set based on entity models.
Let's assume we have these methods:
public Task CommandOne(DbContext context)
{
Entity entity = new Entity
{
Name = "Name"
};
context.DbSet<Entity>().Add(entity);
return context.SaveChangesAsync();
}
public async Task CommandTwo(DbContext context)
{
DbCommand command = context.Database.GetDbConnection().CreateCommand();
command.CommandText = "storedProcName";
command.CommandType = System.Data.CommandType.StoredProcedure;
using (var reader = await command.ExecuteReaderAsync().ConfigureAwait(false))
{
// read result sets
}
}
If I call both commands in one transaction like this:
public async Task UnitOfWork(DbContext dbContext)
{
using (var transaction = await dbContext.Database.BeginTransactionAsync())
{
await CommandOne(dbContext);
await CommandTwo(dbContext);
}
}
This exception happens:
BeginExecuteReader requires the command to have a transaction when the connection assigned to the command is in a pending local transaction. The Transaction property of the command has not been initialized.
I have to mention, it's not as simple as command.Transaction = ...
. This requires DbTransaction
which differs from the transaction EF uses.
I've been stuck with this for a month!
Is there any workaround for this?
Thank you so much.
EF Core relies on database providers to implement support for System. Transactions. If a provider does not implement support for System.
In all versions of Entity Framework, whenever you execute SaveChanges() to insert, update or delete on the database the framework will wrap that operation in a transaction. This transaction lasts only long enough to execute the operation and then completes.
In Entity Framework, the SaveChanges() method internally creates a transaction and wraps all INSERT, UPDATE and DELETE operations under it. Multiple SaveChanges() calls, create separate transactions, perform CRUD operations and then commit each transaction.
I have to mention, it's not as simple as
command.Transaction = ....
This requiresDbTransaction
which differs from the transaction EF uses.
Actually it is. All you need is a reference to Microsoft.EntityFrameworkCore.Relational assembly and add
using Microsoft.EntityFrameworkCore.Storage;
to get access to GetDbTransaction
extension method:
command.Transaction = context.Database.CurrentTransaction?.GetDbTransaction();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With