在 .NET Core 中取消存储过程

Cancel stored procedure in .NET Core

我有一个 table:

CREATE TABLE [dbo].[Semaphores](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nchar](10) NULL
) ON [PRIMARY]

我有一个存储过程:

ALTER PROCEDURE [dbo].[SpCreateLock] @Name nvarchar(50)
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL READ COMMITTED
    BEGIN TRANSACTION
        INSERT INTO Semaphores VALUES (@Name)
        Waitfor delay '00:00:10'
    COMMIT TRANSACTION
END

我有一个简单的控制台 .NET Core 应用程序:

class Program
{
    private static readonly DbContextOptions DbContextOptions;

    static Program()
    {
        var connectionString = "server=(localdb)\ProjectsV13; database=test; trusted_connection=true";

        DbContextOptions = new DbContextOptionsBuilder()
            .UseSqlServer(connectionString)
            .Options;
    }

    static async Task Main(string[] args)
    {
        await TryGetLock();
        Console.ReadKey();
    }

    private async static Task TryGetLock()
    {
        using (var context = new DatabaseContext(DbContextOptions))
        using (var cancellationTokenSource = new CancellationTokenSource())
        {
            var cancellationToken = cancellationTokenSource.Token;

            cancellationTokenSource.CancelAfter(5000);
            cancellationToken.ThrowIfCancellationRequested();

            try
            {
                context.Database.OpenConnection();
                var result = await context.Database.ExecuteSqlCommandAsync("exec SpCreateLock qwerty", cancellationToken);
            }
            catch (OperationCanceledException e)
            {
            }
        }
    }
}

我正在调用 Main 中的 TryGetLock 方法。应用程序启动后,我转到 ssms 并调用一个简单的 select * from Semaphores - 它被暂停(正在执行查询),因为 .NET Core 应用程序正在使用 table(可序列化隔离级别)。在我的应用程序中的查询被取消后,我希望 ssms 中的查询完成 - 但事实并非如此,它显然陷入了僵局。它仅在我关闭我的 .NET Core 应用程序时完成。我尝试关闭、处理数据库连接,但它没有改变任何东西。

我在这里错过了什么?

我最终摆脱了 sql 过程中的事务创建并将其放入 c# 代码中。

sql:

ALTER PROCEDURE [dbo].[SpCreateLock] @Name nvarchar(50)
AS
BEGIN
    INSERT INTO Semaphores VALUES (@Name)
    Waitfor delay '00:00:10'
END

c#:

class Program
    {
        private static readonly DbContextOptions DbContextOptions;

        public static readonly LoggerFactory MyLoggerFactory = new LoggerFactory(new[] { new ConsoleLoggerProvider((_, __) => true, true) });

        static Program()
        {
            var connectionString = "server=(localdb)\ProjectsV13; database=test; trusted_connection=true";

            DbContextOptions = new DbContextOptionsBuilder()
                .UseSqlServer(connectionString)
                .EnableSensitiveDataLogging()
                .UseLoggerFactory(MyLoggerFactory)
                .Options;
        }

        static async Task Main(string[] args)
        {
            await TryGetLock();
            Console.ReadKey();
        }

        private async static Task TryGetLock()
        {
            IDbContextTransaction transaction = null;
            var context = new DatabaseContext(DbContextOptions);
            var cancellationTokenSource = new CancellationTokenSource();

            try
            {
                var cancellationToken = cancellationTokenSource.Token;

                cancellationTokenSource.CancelAfter(5000);
                context.Database.OpenConnection();
                transaction = context.Database.BeginTransaction(IsolationLevel.Serializable);

                var result = await context.Database.ExecuteSqlCommandAsync("exec SpCreateLock qwerty", cancellationToken);

                context.Database.CommitTransaction();
            }
            catch (Exception e)
            {
                context.Database.RollbackTransaction();
            }
            finally
            {
                cancellationTokenSource?.Dispose();
                transaction?.Dispose();
                context?.Dispose();
            }
        }
    }