在没有 For 循环的情况下使用 C# 中数据表中的 ID 更新数据库(SQL 服务器)

Updating a DB (SQL Server) using Ids from a dataTable in C# without For loop

这是我关于 S.O 的第一个问题,而且我在 C# 和 SqlServer 方面还是个新手。 太漂亮了,请客气。

我有一个包含 4 列的数据表:id1、id2、id3、id4(和几行) 我还有一个 SQL 服务器数据库,其中包含 4 列和其他列,其中 2 列名为 field1 和 field2

我想将数据库中的 field1 和 field2 更新为 null(不使用 foreach 行)

我已经成功更新了第一行:

public void UpdateDt(DataTable dt, string ConnectionString)
{
    Conn = null;
    DataRow row =  dt.Rows[0]   
    try
    {

        Conn = new SqlConnection(ConnectionString);
        Conn.Open();
        string sql = "update [DB].[dbo].[MyTable] set [field1] = null,"+
                "[field2] = null where [ID1] = '"+row["ID1"]+"' and [ID2] = '"+row["ID2"]+"' "+
                "and [ID3] = '"+row["ID3"]+"' and [ID4] = '"+row["ID4"]+"'";
        var sqlDataAdapter = new SqlDataAdapter { UpdateCommand = Conn.CreateCommand() };
        sqlDataAdapter.UpdateCommand.CommandText = sql;
        sqlDataAdapter.UpdateCommand.BeginExecuteNonQuery();
    }
    catch( Exception ex) log(ex);
    finally
    { 
        if (Conn != null)
        {
            Conn.Close();       
            Conn.Dispose(); 
        }
    }
}

如何使用整个 DataTable 进行更新?

请帮忙 提前致谢

-- 对 Soner Gönül 评论的回应

我已经根据您的建议修改了示例代码,谢谢

Zohar,谢谢,我选择了字段名称是为了尝试让问题更笼统和更容易理解

---编辑--- 我添加了使用 ForEach 更新整个 DataTable 的代码(在 Russ 的帮助下(感谢 Russ))

 bool UpdateDt(DataTable dt)
        {
            Conn = null;
            try
            {
                Conn = new SqlConnection(ConnectionString);
                Conn.Open();
                string sql = "update [KeywordInjectionData] " +
                                              "set " +
                                              "[field1] = null " +
                                              ",[field2] = null " +
                                              "where " + 
                                              "[Id1] = @Id1" +
                                              " and [Id2] = @Id2" +
                                              " and [Id3] = @Id3" +                                                                   
                                              " and [Id4] = @Id4;" ;


                var sqlDataAdapter = new SqlDataAdapter { UpdateCommand = Conn.CreateCommand() };
                foreach (DataRow row in dt.Rows)
                {
                    sqlDataAdapter.UpdateCommand.CommandText = sql;
                    sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("@Id1",row["Id1"]);
                    sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("@Id2",row["Id2"]);
                    sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("@Id3",row["Id3"]);
                    sqlDataAdapter.UpdateCommand.Parameters.AddWithValue("@Id4",row["Id4"]);
                    sqlDataAdapter.UpdateCommand.ExecuteNonQuery();
                    sqlDataAdapter.UpdateCommand.Parameters.Clear();
                }
            }
            catch (Exception e1)
            {
                Utillties.LogError(e1);
                return false;
            }

            finally
            {
                if (Conn != null)
                {
                    Conn.Close();
                    Conn.Dispose();
                }
            }
            return true;
        }

但问题仍然存在,如何在没有 ForEach 循环的情况下更新数据库?

首先,您构建查询的方式非常危险,因为它会允许 SQL 注入——您应该只使用参数化查询(正如 Soner Gonul 在上面的评论中提到的)。

其次,您可以使用 Foreach 子句遍历每一行:

Foreach (DataRow row in dt.Rows)

然而,在执行此操作时,您应该将连接声明和打开移动到 Foreach 之前,以便您只打开连接一次。

我不确定您为什么不想在这种情况下使用循环。一般来说,在纯数据库级别,循环被认为是 "bad",但这实际上是对问题的过度简化......(我写了很多查询,有循环比没有循环更快)

让我们从问题中删除 C# 开始,改为 "how to update all desired rows in a table at once?" 因为新值都是相同的,所以这是可能的,前提是您可以创建适当的 where 子句。在这种情况下,由于您试图根据(我假设)用户输入更新一组随机行,因此它需要如下所示:

UPDATE dbo.MyTable
SET field1 = null, field2 = null
WHERE (id1 = @m1_id1 AND id2 = @m1_id2 AND id3 = @m1_id3)
      OR (id1 = @m2_id1 AND id2 = @m2_id2 AND id3 = @m2_id3)
      OR (id1 = @m3_id1 AND id2 = @m3_id2 AND id3 = @m3_id3)
etc.

这很愚蠢而且很快。为了完整起见,如果您在数据库中引用另一个 table,则可以执行以下操作(在大多数 RDBMS 下):

UPDATE myT
SET field1 = null, field2 = null
FROM dbo.MyTable myT
    JOIN dbo.SetsToUpdate s ON myT.id1=s.id1
                            AND myT.id2=s.id2
                            AND myT.id3=s.id3

但是,您并不是从另一个 table 开始,设置一个、填充它并清理它很可能需要比简单的多个单行更新更多的资源。

所以,我们回到了一个循环,但是在 C# 中执行的循环非常有效。此外,除了性能之外,需要单个 update 语句的唯一其他原因是数据原子性,transactions.

可以很好地处理它

如果您确实在此处看到数据库级别的性能问题,那么问题就是数据库优化之一(查看 indexes)。但是,请不要陷入过早优化的陷阱。