【问题标题】:C# - Using DataAdapter to Update SQL table from a DataTable - SQL table not updating [closed]C# - 使用 DataAdapter 从 DataTable 更新 SQL 表 - SQL 表不更新 [关闭]
【发布时间】:2011-12-31 13:56:48
【问题描述】:

我将 select * from 一个 Excel 电子表格转换为 DataTable dt。我想获取这些值并更新 SQL 表。 SQL 表的存在是因为从原始 Excel 电子表格手动导入 SQL,具有主键集。用户更新了 excel 表,我需要更新 SQL 值。我将dt.RowState 设置为修改以调用更新。我没有收到错误,但 SQL 表没有更新。之前的测试显示我的SQL权限和连接都很好,可以修改表了。

connectionToSQL = new SqlConnection(SQLConnString);
connectionToSQL.Open();
var cmd = new SqlCommand("SELECT * FROM TAGS$",connectionToSQL);                 
var da = new SqlDataAdapter(cmd);
var b = new SqlCommandBuilder(da);
foreach (DataRow r in dt.Rows)
{
    r.SetModified();
}
da.Update(dt);   

【问题讨论】:

  • 提供的代码中没有任何内容可以实际修改任何 DataRow 对象,也没有让我们了解您希望能够修改的数据库中的任何示例列名。请在 foreach 循环中添加一个修改列值的示例,然后自己再次测试您仍然没有看到执行的 UPDATE 语句,我们可以深入研究。
  • 这个 dt 是从哪里来的?尝试分配您的数据表,因为您的 foreach 没有循环任何内容?
  • 您是否考虑过使用SQL profiler 来查看是否有任何SQL 实际进入SQL 服务器?
  • dt 来自“我从 Excel 电子表格中选择 * 到 dt”。
  • 我没有修改 dt 中的值。请重新阅读问题。来自 excel 的 dt 中的值与 SQL 表中的值不同。 foreach 循环手动将行状态设置为“已修改”以调用 UPDATE。

标签: c# dataadapter rowstate


【解决方案1】:

试试这个:

using System.Data;
using System.Data.SqlClient;
using System;
namespace Q308507 {
    class Class1 
    {
        static void Main(string[] args) 
        {
            SqlConnection cn = new SqlConnection();
            DataSet CustomersDataSet = new DataSet();
            SqlDataAdapter da;
            SqlCommandBuilder cmdBuilder;
            // Set the connection string of the SqlConnection object
            // to connect to the SQL Server database in which you
            // created the sample table.
            cn.ConnectionString =
            "Server=server;Database=northwind;UID=login;PWD=password;";
            cn.Open();      
            // Initialize the SqlDataAdapter object by specifying a
            // Select command that retrieves data from the sample table.
            da = new SqlDataAdapter("select * from CustTest order by CustId", cn);
            // Initialize the SqlCommandBuilder object to automatically
            // generate and initialize the UpdateCommand,
            // InsertCommand, and DeleteCommand properties
            // of the SqlDataAdapter.
            cmdBuilder = new SqlCommandBuilder(da);
            // Populate the DataSet by running the Fill method
            // of the SqlDataAdapter.
            da.Fill(CustomersDataSet, "Customers");
            // Display the Update, Insert, and Delete commands
            // that were automatically generated
            // by the SqlCommandBuilder object.
            Console.WriteLine(
                "Update command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(
                cmdBuilder.GetUpdateCommand().CommandText);
            Console.WriteLine("         ");
            Console.WriteLine(
                "Insert command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(cmdBuilder.GetInsertCommand().CommandText);
            Console.WriteLine("         ");        
            Console.WriteLine(
                "Delete command Generated by the Command Builder : ");
            Console.WriteLine(
                "==================================================");
            Console.WriteLine(cmdBuilder.GetDeleteCommand().CommandText);
            Console.WriteLine("         ");
            // Write out the value in the CustName field before
            // updating the data using the DataSet.
            Console.WriteLine("Customer Name before Update : " +
                CustomersDataSet.Tables["Customers"].Rows[0]["CustName"]);
    
            // Modify the value of the CustName field.
            CustomersDataSet.Tables["Customers"].Rows[0]["CustName"] = "Jack";
            // Post the data modification to the database.
            da.Update(CustomersDataSet, "Customers");        
            Console.WriteLine("Customer Name updated successfully");
            // Close the database connection.
            cn.Close();
            // Pause
            Console.ReadLine();
        }
    }
}

【讨论】:

  • 这并不适用。我不会修改我的数据表中的值。由于用户对源 Excel 工作表的输入,它们与 SQL 表不同。
  • 问题实际上是让数据表看起来像已被修改,因此它对所有行执行更新。
【解决方案2】:

我认为 SqlCommandBuilder 生成的自动生成的 SqlCommands 并不适合您的情况(如果我正确理解了这个问题)。在 SqlCommandBuilder 生成的 SQL Update 语句的 WHERE 子句中,将所有列的值与其原始值(由 DataRow 中的原始数据值确定)进行比较。如果目标数据库中的原始值不匹配,则不会更新任何行。

这个指向 SqlCommandBuilder 的链接可能会有所帮助:

http://msdn.microsoft.com/en-us/library/ms971491.aspx

从该链接中,尝试理解:“adCriteriaAllCols”,因为这是 SqlCommandBuilder 使用的。我怀疑你想要的是“AdCriteriaKey”行为。

一种可能的解决方案可能是不使用 SqlCommandBuilder,而只需自己编写 INSERT/UPDATE/DELETE SqlCommand,并将它们附加到 SqlDataAdapter.InsertCommand、UpdateCommand 和 DeleteCommand。
有一些示例代码在:http://support.microsoft.com/kb/308055

EDIT:.net 2.0 及更高版本中的 SqlCommandBuilder 具有 ConflictOption 属性。默认使用的是:CompareAllSearchableValues。尝试使用:OverwriteChanges,这会导致SQL语句中生成的WHERE子句只比较主键值。

【讨论】:

  • 是的,我正朝着这个方向前进。我目前正在寻找一些旧代码,我“认为”我已经完成了我正在尝试使用 excel 和数据库做的事情。虽然它一定是 OleDbAdapter,但我想知道是否有区别。 Alex 建议用 Excel 中的数据覆盖我从 SQL 中选择的数据,这可能是(稍微)更有效的方法。
  • 顺便说一句,你是 100% 正确的。我已经查看了文本可视化器中的更新命令,它不会更新任何内容。但是再一次 - 我一直在以某种方式记住以前做过这件事 - 所以我还是这么想。如果我找到它并让它工作,我会发布代码。
  • 实际上,可以让命令生成器仅根据主键进行更新。试试: sqlCommandBuilder.ConflictOption = ConflictOption.OverwriteChanges
【解决方案3】:

我尝试发表评论,但被告知要重新阅读问题。所以我做了,但它没有帮助:) 在那个例子中你只有很少的代码将dt(你说这是从 Excel 填充的)与数据库联系起来。您有变量connectionToSQLcmddab。这些连接到数据库。然后您遍历dt,但事实并非如此。这就是为什么在我的评论中我要求提供示例源代码,您正在修改 dt 中的行 - 因为我假设您会在某个地方拥有它,以便期望更改会从 Excel(填充 dt)跳转到您的数据库。

我看到您正在调用 da.Update(dt); 尝试从数据库中打开一个新数据集,并遍历 dt 中的行,将更改应用于新数据集中的行。据我所知——那里没有太多代码——没有发出任何命令,因为数据适配器知道dt 的内部行不是来自其数据源。无论如何,那是我的刺。

【讨论】:

  • 谢谢亚历克斯。我想我在这里看到了你的思考过程。让我尝试添加更多信息。 excel 中的更改发生在最终用户的 excel 内部。他们保存更改并关闭工作簿并将其交给我。然后我运行我的程序并从 Excelworkbook 中选择 * 到 dt。此时 dt 是一个数据表,其中包含一些值。它是未修改的。 dt 中的值与从原始 Excel 导入的 SQL 表不同。
  • 所以我在内存中有一个 dt,它只是一个未修改的数据表,但我想将它发送到 SQL,因为“我”知道数据是(或可能)不同的。因此,我遍历它以将 rowstate 设置为 modified 以调用 Update 命令来处理表。这是我在桌子上做的唯一工作。所以我的问题是即使我将所有行都设置为“修改”,更新命令也没有做任何事情。 (我可以在这里粘贴所有 ImportExcel 代码,但它很多,除了用工作表中的所有内容填充 dt 之外什么也不做。
  • 感谢您的澄清 - 我已经明白了,但我的意思是您正在隐式更改所有这些行的后备存储。只需将行标记为已修改,然后将整个数据集的更新发布到使用另一个源的 DataAdapter 就不会(AFAIK)发布更新。因此我的建议(部分作为诊断操作)是从目标数据源创建一个单独的数据集,并在发布更新之前将值复制到循环中。
  • 啊,我明白你现在在说什么了。是的,理论上应该可行。
  • ******我没有将行设置为“已修改”,而是将行设置为“添加”(使用循环),然后 da.update 按预期工作。***** *
猜你喜欢
  • 2011-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多