简体   繁体   中英

EF Core 2.0 TransactionScope Error

I am trying to use TransactionScope in my SELECT query in EntityFramework Core 2.0. However I am getting this error : "Enlisting in Ambient transactions is not supported."

The idea is to implement "NO LOCK" option (I know it's not a good idea to have that option in place but it's vendor's requirement) when I do select query. So I added an extension method ( Entity Framework with NOLOCK )

public static async Task<List<T>> ToListReadUncommittedAsync<T>(this IQueryable<T> query)
{
    using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew,
        new TransactionOptions()
        {
            IsolationLevel = IsolationLevel.ReadUncommitted
        }, TransactionScopeAsyncFlowOption.Enabled))
    {
        var result = await query.ToListAsync();
        scope.Complete();
        return result;
    }
}

And also I have set to ignore the Ambient Transaction Warning.

public static void AddEntityFramework(this IServiceCollection services, string connectionString)
{
    services.AddDbContextPool<OptomateContext>(options =>
    {
        options.UseSqlServer(connectionString);
        options.ConfigureWarnings(x => x.Ignore(RelationalEventId.AmbientTransactionWarning));
    });
}

And I have the query as below in my repository

public async Task<Patient> GetPatient(Common.Resources.Patient patient)
{
    var pat = await Dbset.Where(x => string.Equals(x.Surname,patient.Surname, 
    StringComparison.CurrentCultureIgnoreCase)).ToListReadUncommittedAsync();                                    

    return pat.FirstOrDefault();
}

I understood that .Net Core 2.0 supports TransactionScope. but I am not sure why I am getting this exception.

Any idea why is this happening?

System.Transactions are not supported yet in EF Core. The issue is tracked by #5595: Enable support for System.Transactions and is committed to be included in the next EF Core release 2.1 . ( Update: EF Core 2.1 indeed added System.Transactions support ).

Until then, if the whole point is to use transaction with ReadUncommitted , you can try using the explicit EF Core IDbTransaction through BeginTransaction(DatabaseFacade, IsolationLevel) extension method. Unfortunately it cannot be fully encapsulated like in your current custom extension method and requires passing the DbContext instance:

public static async Task<List<T>> ToListReadUncommittedAsync<T>(this IQueryable<T> query, DbContext context)
{
    using (var transaction = await context.Database.BeginTransactionAsync(System.Data.IsolationLevel.ReadUncommitted))           {
    {
        var result = await query.ToListAsync();
        transaction.Commit();
        return result;
    }
}

I found a workaround that don't use transaction scopes for each query. If you run the code below, ef will use the same transaction isolation level for the same Server Process ID. Since Server Process ID does not change in same request, only one call for each request is sufficient.

this.Database.ExecuteSqlCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM