简体   繁体   中英

How to kill ambient transaction?

I have a program, which is related to database. I need to unit-test some methods from class, which represents repository. I've decided to do it without localdb , but using Rollback attribute implementation:

public class Rollback : Attribute, ITestAction
{
    private TransactionScope transaction;

    public void BeforeTest(ITest test)
    {
        transaction = new TransactionScope();
    }

    public void AfterTest(ITest test)
    {
        transaction.Dispose();
    }

    public ActionTargets Targets => ActionTargets.Test;
}

I've got that from the Internet. This attribute implicitly begins transaction before method's code, and rolls it back after. That really works nice.

But at one moment I've wanted to debug this test:

    [Test, Rollback]
    public async Task AddingExistingDictionaryTypeThrowsExceptionTest()
    {
        await _repository.AddDictionaryType(tempDictionaryTypeName, tempDictionaryTypeDescription);

        Assert.ThrowsAsync<Exception>(async () => { await _repository.AddDictionaryType(tempDictionaryTypeName, tempDictionaryTypeDescription); });
    }

AddDictionaryType - is a method from repository. It adds new entity to database after checking, if such record doesn't exist already:

    public async Task AddDictionaryType(string name, string description)
    {
        try
        {
            var sameNameCollection = _dbContext.DictionaryTypes.FromSqlRaw(@$"select * from dictionary_type where name = '{name}'");
            var sameDescriptionCollection = _dbContext.DictionaryTypes.FromSqlRaw(@$"select * from dictionary_type where description = '{description}'");

            if (sameNameCollection.Any() || sameDescriptionCollection.Any())
            {
                throw new AddingExistingDictionaryException();
            }

            _dbContext.Add(new DictionaryType(name, description));
            await _dbContext.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            throw ex;
        }            
    }

Don't pay attention to two SELECTS , I know, that I may make one check, but that's for my needs.

So, I've set the point after first call of AddDictionaryType method to check new record in database, after that I've done SELECT in SSMS (I know, that was silly, too, because method worked in transaction) from same table, in which I've tried to insert record. So, I've got an error. And now I will tell you about most interesting:

After that I can't normally execute the test, I always get error: "This connection was used with the ambient transaction. The original ambient transaction needs to be completed before this connection can be used outside of it".

So I think, that there is that transaction, which hasn't been closed.

The problem is that I cannot find it and kill.

I've operated with such queries to find it:

SELECT * FROM sys.sysprocesses;

SELECT * from sys.dm_tran_current_transaction with(nolock);

SELECT * from sys.dm_tran_active_transactions;

EXEC SP_who2;

SELECT * FROM sys. dm_exec_sessions;

SELECT * FROM fn_dblog(NULL, NULL);

I've seen processes, tried to kill them, didn't help. I've reloaded server, didn't help. There is no any information about such transaction in transaction log.

No I see, that testing like this is a big problem, because I don't even know, how that transaction could be named to rollback it by my hands.

May be it's not because of transaction? But I don't have any ideas. What about you?

I've refused using Rollback attribute, but follow Charlieface's advice. Now I use using statement in each test, and everything works nice:

    [Test]
    public async Task Test()
    {
        using (var tran = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
        {
            // test logic
        }
    }

Also, I've understodd, that there is know any stuck transaction in database.

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