【问题标题】:Query not being executed on database when using DbCommand.ExecuteNonQueryAsync() > 0;使用 DbCommand.ExecuteNonQueryAsync() > 0 时未在数据库上执行查询;
【发布时间】:2020-09-14 07:16:15
【问题描述】:

我正在尝试对我们的数据库执行查询,我已在文本中创建它,因为我无法在 Entity Framework Core 中使其足够高效。

这是我正在使用的代码,但它似乎没有在数据库上执行(我在数据库上没有看到此交易的记录),但我也没有收到任何错误。我做错了什么?

    public async Task<CleanupObservationsResponse> Handle(CleanupObservationsCommand request, CancellationToken cancellationToken)
    {
        var removalDate = DateTime.Now.AddMonths(-3);
        _logger.LogInformation($"Started cleaning up observations for all observations before {removalDate.Date.ToString("yyyy-MM-dd")}");
        await _observationRepository.CleanupObservations(removalDate);
    }

    public Task<bool> CleanupObservations(DateTime removalDate)
    {
        var sql = $"START TRANSACTION;" +
        $"SET @RemovalDate := \"{removalDate.ToString("yyyy-MM-dd")}\";" +
        $"# MySql Variables can only store 1 row and thus the results of this query cannot be saved in a variable." +
        $"# SET @observationsToDelete := (SELECT Identification FROM cpp.Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM PropertyValues WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM HoldReasonObservation WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM ObservationDeviation WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM ObservationQRTokens WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM ObservationTarra WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM Alibi WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM PackageTrackingIdentifications WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM QuestionAnswer WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);" +
        $"DELETE FROM Observation WHERE StartedUtc < @RemovalDate;" +
        $"COMMIT;";

        return this.ExecuteSQL(sql);
    }

    private async Task<bool> ExecuteSQL(string sql)
    {
        var connection = Context.Database.GetDbConnection();
        using (var cmd = connection.CreateCommand())
        {
            cmd.CommandText = sql;
            cmd.CommandType = CommandType.Text;

            if (connection.State != ConnectionState.Open)
            {
                connection.Open();
            }

            return await cmd.ExecuteNonQueryAsync() > 0;
        }
    }

【问题讨论】:

  • 你应该等待 this.ExecuteSQL(sql);
  • @Ayoub_B 是的,我意识到我没有包含该代码,我在调用堆栈中执行了 1 个方法(现在也将其添加到问题中)
  • 你能不能试着把它包装在一个try-catch中,也许会抛出一个异常但它被吞噬了
  • 堆栈中有一个更高的尝试追赶,它总是会记录它,但我可以尝试
  • 不,仍然没有错误。

标签: c# mysql .net-core


【解决方案1】:

在 MySQL 中,以# 开头的注释会延伸到行尾。 (见https://dev.mysql.com/doc/refman/8.0/en/comments.html。)

您的原始 SQL 代码中没有换行符,因此以 # MySql Variables can only store 开头的注释包含所有剩余文本,并且没有执行任何操作。

我会将该字符串重写为使用逐字 C# 字符串(不是插值字符串):

var sql = @"START TRANSACTION;
        SET @RemovalDate := ""{removalDate.ToString("yyyy-MM-dd")}"";
        # MySql Variables can only store 1 row and thus the results of this query cannot be saved in a variable.
        # SET @observationsToDelete := (SELECT Identification FROM cpp.Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM PropertyValues WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM HoldReasonObservation WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM ObservationDeviation WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM ObservationQRTokens WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM ObservationTarra WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM Alibi WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM PackageTrackingIdentifications WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM QuestionAnswer WHERE ObservationIdentification IN(SELECT Identification FROM Observation WHERE StartedUtc < @RemovalDate);
        DELETE FROM Observation WHERE StartedUtc < @RemovalDate;
        COMMIT;";

最好删除你的 SQL 变量 (SET @RemovalDate := ""{removalDate.ToString("yyyy-MM-dd")}"";) 并使用真正的命令参数:

cmd.Parameters.AddWithValue("@RemovalDate", removalDate);

这将允许 MySQL 连接器为您正确格式化日期,并有助于避免 SQL 注入。

【讨论】:

  • 这确实是问题所在,我永远不会意识到这一点,谢谢。还按照您的建议将其设置为参数,我没有这样做是因为我想回收执行 SQL 方法,但最终您是对的,这是一种更好的方法
【解决方案2】:

也许连接没有打开? 你打电话给connection.Open(); 然后cmd.ExecuteNonQueryAsync()

也许您可以尝试使用 OpenAsync。 如果可用,取决于您的连接器。

【讨论】:

  • 使用 System.Data.Common 命名空间中的 DbCommand 类。它有一个异步方法,但我一直在使用像这样的正常打开方法来处理其他一些查询(这只是 1 个单独的选择语句,我使用 DbCommand.reader 而不是 ExecuteNonQuery 并且这些工作(但我不能将阅读器用于这是因为它不返回任何值)。
  • 给 OpenAsyc 一个机会或执行一次同步。询问。如果查询抛出异常,您可能不会得到它,因为异步操作并且您没有等待'return this.ExecuteSQL(sql);'
猜你喜欢
  • 1970-01-01
  • 2018-07-31
  • 2021-08-17
  • 1970-01-01
  • 2016-02-25
  • 1970-01-01
  • 1970-01-01
  • 2021-05-09
  • 1970-01-01
相关资源
最近更新 更多