C# SQLAdapter插入到不同的表中

C# SQLAdapter插入到不同的表中,c#,datagridview,sqldataadapter,C#,Datagridview,Sqldataadapter,我想创建一个函数,可以同时更新旧表并记录更改前的数据。(类似于日志表。)我创建了一个表来检索我搜索的表,另一个表来存储更改前的表。这两个表在列上有一些不同。 DS是检索数据集,ADS是只进行插入的日志数据集 private void Update_Button_Click(object sender, EventArgs e) { try { //Update table1 SqlCmb = new SqlC

我想创建一个函数,可以同时更新旧表并记录更改前的数据。(类似于日志表。)我创建了一个表来检索我搜索的表,另一个表来存储更改前的表。这两个表在列上有一些不同。 DS是检索数据集,ADS是只进行插入的日志数据集

private void Update_Button_Click(object sender, EventArgs e)
    {
        try
        {
            //Update table1
            SqlCmb = new SqlCommandBuilder(SqlAd);
            SqlAd.Update(DS, "dataset1");

                //INSERT table1_log
                DataSet ds = new DataSet();
                ds = ADS;
                ds.Tables[0].Columns.Add("USER_NAME", typeof(string));
                ds.Tables[0].Columns.Add("UNIQ", typeof(String));
            foreach (DataRow dr in ds.Tables[0].Rows)
                {
                    dr["USER_NAME"] = Form1.USER_NAME.Text;
                    dr["ALTER_TIME"] = DateTime.Now;
                }
                SqlDataAdapter SqlAdI = new SqlDataAdapter("SELECT * FROM table1_log where 0 = 1", SqlCon);
                SqlCommandBuilder SqlCmbI = new SqlCommandBuilder(SqlAdI);

                SqlCom= new SqlCommand("INSERT INTO table1_log FROM" + ds.Tables[0], SqlCon) ;
                SqlAdI.InsertCommand = SqlCom;
                SqlAdI.Update(ADS, "table1");


            MessageBox.Show("Info updated", "Update", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
        catch(Exception ex)
        {
            MessageBox.Show(ex.Message,"Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
我的问题是它无法插入到日志表中,但更新到表1也可以。Uniq是sql server自动生成的主键。错误消息为“并发冲突:update命令影响了预期的1条记录中的0条。”


谢谢大家!

如评论中所述,您应该创建一个触发器。触发器不会使您的代码复杂化或使您不再使用DataGridView,它实际上会使您的代码更简单(在我看来,您的代码有几个问题,但我将尝试解决这个问题)。触发器是在数据库级别实现的,而不是在C#代码中实现的。它将消除在代码中显式编写insert语句的需要,如果您曾经编写过需要记录的多个语句(如insert、update、delete),这将特别有用。您只需编写insert to log语句一次,它就会一直运行

我想知道插入的问题是否是因为日志表的主键与表1的主键匹配。在这种情况下,单个记录可能会被更新多次,并尝试使用相同的密钥,而该密钥可能已经存在于日志中。最简单的修复方法是在日志表中添加一个新的主键,它只是一个在每次插入时递增的顺序id。我还建议添加另一列,以指示执行的操作类型(即插入、更新、删除)。下面是一个很好的答案,解释了如何检测操作:

更重要的一点是,您正在通过连接字符串来构建insert语句。我不完全确定ds.Tables[0]中的值来自何处,但您将其直接连接到insert语句中,如果这是用户输入,则会使您面临SQL注入攻击的风险。攻击者可以相当容易地窃取或删除数据。即使在其他地方进行了检查,我仍然建议使用SqlParameter,这样其他看到您的代码的人就可以清楚地知道您正在防范这些危险

用于在sql中创建触发器的伪代码:

CREATE TRIGGER TR_TABLE1_AUDIT
ON table1
FOR INSERT, UPDATE, DELETE
AS
  -- your insert statement here
  INSERT INTO table1_log ...
编辑:添加有关防范SQL注入攻击的信息。 不管您允许用户输入多少字段,这与SQL注入攻击完全无关。为了防止这种情况,您不能将用户输入直接连接到SQL语句中。您需要这样做:

// Set the command text (you could pass this in the constructor)
sqlcom.CommandText = "select * from table1 where loc = @loc ";
// Create SqlParameter
// Note that I don't know your actual SqlDbType, replace it with whatever it should be
SqlParameter param = new SqlParameter("@loc", SqlDbType.Varchar) { Value = loc };
// Add to SqlCommand parameter collection
sqlcom.Parameters.Add(param);
// Add the command to your SqlDataAdapter if you are using one

这称为参数化。参数化用户输入的任何内容都可以防止SQL注入。您可以将SqlParameter与Add语句内联以缩短时间。

您有能力使用库吗?如果可以的话,看看整洁会让你的生活更轻松,你是什么意思?我可以成功地更新到表1,但无法插入到表日志中,因此我认为我有能力使用库。@ericka08:您应该查找触发器。这是在更新另一个表时更新表的一种好方法。您可以向表中添加触发器,这样它就可以自动更新日志表,而无需使用SQLCommand并跟踪代码中所做的更改。我们在工作中一直使用这些工具来对日志表进行uddate,方法与您所寻找的相同。我会试着找一个link@JSON我正在使用datagridview,我希望我能坚持使用它。这使我的代码非常简单。我会看一看,但这将是我的最后一次尝试。非常感谢。嗨,布兰登,我正在制作一个触发器。对于主键问题,我创建了一个变量“UNIQ”来处理,它与原始变量不同。对于sql注入问题,我只允许用户向sql中输入一个变量。看起来是这样的:
从表1中选择*,其中loc=“+loc+”
不确定这是否会阻止sql注入,因为我对这一点非常陌生。我对您关于主键的声明有点困惑。主键是唯一的标识符,表中的每一行始终具有1:1的比率。如果您声称表主键不是1对1,那么根据定义它不是主键。@erickao08我刚刚编辑了我的回答,以提供有关防范SQL的更多信息injection@JSON这正是我的观点,据我所知,海报希望使用与主键相同的UID,这将不起作用,因为在日志/归档表中,同一对象可能有多个编辑记录。因此,应该添加一个额外的列,称为log_id,作为主键。然后将table1的uid作为外键添加到日志表中,以便您可以查看记录的更改历史。@JSON和Brandon UNIQ是我的日志id,是1对1。我创建了2个数据集来存储我的表;然而他们是不同的。ADS是以UNIQ作为主键的日志表。DS有它的原始PK,所以我不会插入任何内容。日志表外键将是表1的主键。