Sql server 在实体框架进行更改之前暂停Azure功能

Sql server 在实体框架进行更改之前暂停Azure功能,sql-server,azure,entity-framework-core,azure-functions,azure-iot-hub,Sql Server,Azure,Entity Framework Core,Azure Functions,Azure Iot Hub,我有一个Azure功能(Iot集线器触发器): 选择按时间降序排列的前1条记录 与新记录相比 仅当未来记录与所选记录不同(某些字段不同)时才写入该记录 当记录很快进入azure功能时,问题就出现了——我最终在数据库中发现了重复的记录。我猜这是因为SQL Server没有足够的时间在下一条记录出现和Azure函数选择时在数据库中进行更改,而当Azure函数选择最新记录时,它实际上接收到一条过期记录 我使用EF Core。我确实认为功能没有问题,但您描述的操作的事务性质有问题。为了简单地解决您的问题

我有一个Azure功能(Iot集线器触发器):

  • 选择按时间降序排列的前1条记录
  • 与新记录相比
  • 仅当未来记录与所选记录不同(某些字段不同)时才写入该记录
  • 当记录很快进入azure功能时,问题就出现了——我最终在数据库中发现了重复的记录。我猜这是因为SQL Server没有足够的时间在下一条记录出现和Azure函数选择时在数据库中进行更改,而当Azure函数选择最新记录时,它实际上接收到一条过期记录


    我使用EF Core。

    我确实认为功能没有问题,但您描述的操作的事务性质有问题。为了简单地解决您的问题,您可以尝试使用具有最高隔离级别的事务:

            using (var transaction = new TransactionScope(
                TransactionScopeOption.Required,
                new TransactionOptions
                {
                    // With this isolation level all data modifications are sequential
                    IsolationLevel = IsolationLevel.Serializable
                }))
            {
                using (var connection = new SqlConnection("YOUR CONNECTION"))
                {
                    connection.Open();
    
                    try
                    {
                        // Run raw ADO.NET command in the transaction
                        var command = connection.CreateCommand();
                        // Your reading query (just for example sake)
                        command.CommandText = "SELECT TOP 1 FROM dbo.Whatever";
                        var result = command.ExecuteScalar();
    
                        // Run an EF Core command in the transaction
                        var options = new DbContextOptionsBuilder<TestContext>()
                            .UseSqlServer(connection)
                            .Options;
    
                        using (var context = new TestContext(options))
                        {
                            context.Items.Add(result);
                            context.SaveChanges();
                        }
    
                        // Commit transaction if all commands succeed, transaction will auto-rollback
                        // when disposed if either commands fails
                        transaction.Complete();
                    }
                    catch (System.Exception)
                    {
                        // TODO: Handle failure
                    }
                }
            }
    
    使用(var事务=新事务范围)(
    TransactionScopeOption。必需,
    新交易选项
    {
    //使用此隔离级别,所有数据修改都是顺序的
    IsolationLevel=IsolationLevel.Serializable
    }))
    {
    使用(var connection=newsqlconnection(“您的连接”))
    {
    connection.Open();
    尝试
    {
    //在事务中运行原始ADO.NET命令
    var command=connection.CreateCommand();
    //你的阅读查询(只是为了举例)
    command.CommandText=“从dbo.Whatever中选择顶部1”;
    var result=command.ExecuteScalar();
    //在事务中运行EF Core命令
    var options=new DbContextOptionsBuilder()
    .UseSqlServer(连接)
    .选择;
    使用(var context=newtestcontext(选项))
    {
    context.Items.Add(结果);
    SaveChanges();
    }
    //提交事务如果所有命令都成功,事务将自动回滚
    //如果其中一个命令失败,则释放该命令
    transaction.Complete();
    }
    捕获(系统异常)
    {
    //TODO:处理失败
    }
    }
    }
    
    您应该根据需要调整代码,但您有一个想法


    尽管如此,我还是希望完全避免这个问题,不修改任何记录,而是插入它们,然后选择最新的记录。事务在应用程序中很棘手,它们可能会导致性能下降,并导致死锁以错误的方式应用在错误的位置。

    我不是在修改记录。我正在选择和插入。在插入完成之前,您的代码是否锁定任何选择?确切地说,IsolationLevel.Serializable阻止其他用户在事务完成之前更新或将行插入表中。在这里阅读关于可序列化隔离级别的更多信息:在这里:我已经检查了您的建议,但仍然得到了连续的副本。我用一个代码示例更新了我的问题。请你看看好吗?