“不返回任何键列信息的SelectCommand不支持UpdateCommand的动态SQL生成”问题

来源:互联网 发布:网络监测平台 编辑:程序博客网 时间:2024/05/02 01:48

“不返回任何键列信息的SelectCommand不支持UpdateCommand的动态SQL生成”问题  

2008-11-14 22:09:22|  分类: ADO.NET|字号 订阅

        今天在讲ATA的ADO.NET2.0里面的一个案例的时候,出现了一个问题。具体的说,就是在使用DataAdapter进行数据更新的时候,出现了一个“不返回任何键列信息的SelectCommand不支持UpdateCommand的动态SQL生成”错误。

          当我们使用适配器从数据库中读到数据,然后填充到DataSet中以后,如何要更新数据,那么,需要先改变DataSet中数据的值(也就是内存中的“副本”的值),然后再更新数据库,或者说叫同步数据库。一般我们都是使用SqlCommandBuilder来完成的(当然,如果出于性能考虑,还可以直接指定命令而不使用CommandBuilder,另外,也不宜使用 CommandBuilder 来更新参与外键约束的列)。

          出现这个错误的主要原因是:

1、数据库中的表没有指定主键!因为我们更新数据,是先更新DataSet中的数据,然后同步数据库里面相应的表,这就需要主键来查找相关的记录,从而实现更新(所以,大家会发现,updateCommand和DeleteCommand就会出错,但是InsertCommand却不会出错)。

2、需要在DataSet中指定表的主键,或者让它自动带上相关的表架构,也就是说select语句中必须有select 主键字段 from ……。

这里直接将演示代码粘贴出来得了:

表的结构如图所示:

数据更新时的“不返回任何键列信息的SelectCommand不支持UpdateCommand的动态SQL生成”问题 - mralex119 - alexs blog

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace ConsoleApplication1
{
    class Program
    {
        SqlConnection scon;
        string strcon;
        SqlDataAdapter sda;
        SqlCommand scmd;
        DataTable employeeDataTable;
        DataSet ds;
        SqlCommandBuilder scb;

        public Program()
        {
            strcon = "Data Source =localhost; Initial Catalog=adventureWorks; Integrated Security=yes";
            scon = new SqlConnection(strcon);
            scmd = scon.CreateCommand();
            scmd.CommandText = "select EmployeeID,Title from dbo.Employees";
            sda = new SqlDataAdapter(scmd);
            ds=new DataSet();
            employeeDataTable = new DataTable("Employees");
            ds.Tables.Add(employeeDataTable);
            
            sda.Fill(ds,"Employees");
           employeeDataTable.PrimaryKey = new DataColumn[] { employeeDataTable.Columns["EmployeeID"]};

           //出错就是因为少了上面这一句。这条语句指定了DataTable的主键。或者用下一条语句也可以,下一条语句是让适配器自动加上表的架构(Key约束)
         //   sda.MissingSchemaAction = MissingSchemaAction.AddWithKey;

        }
        public void actionOne()
        {
            DataRow dr = employeeDataTable.NewRow();


            dr = employeeDataTable.Rows[0];
            dr["EmployeeID"] = 11;                       //要在DataTable中修改一行数据
           

            dr = employeeDataTable.NewRow();
            dr["EmployeeID"] = 99;
            dr["Title"] = "vice president";
            employeeDataTable.Rows.Add(dr);     //要往DataTable中插入一行数据

            dr = employeeDataTable.Rows[1];
            dr.Delete();                                          //要删掉DataTable中的一行数据

                scb = new SqlCommandBuilder(sda);       //使用SqlCommandBuilder
           
                sda.UpdateCommand = scb.GetUpdateCommand();    
                Console.WriteLine("update command : " + sda.UpdateCommand.CommandText+"\n");

            //通过CommandBuilder来获得命令,并打印在控制台;后面是不同的命令类型

                sda.InsertCommand = scb.GetInsertCommand();
                Console.WriteLine("insert command: " + sda.InsertCommand.CommandText+"\n");

                sda.DeleteCommand = scb.GetDeleteCommand();
                Console.WriteLine("delete command : " + sda.DeleteCommand.CommandText + "\n");

            sda.Update(ds,"Employees");      //更新Employees表

            ds.Acceptchanges(); //更新完数据源以后,在dataset中接受变化,更新数据集
        }
  
        static void Main(string[] args)
        {
            Program p=new Program();
            p.actionOne();
           
        }
    }
}

代码可以直接ctrl+c 拷贝

关于如何显式指定命令来更新数据源,我直接拷贝了一段msdn上的代码,大家可以参考以下:

private static void AdapterUpdate(string connectionString)

{

    using (SqlConnection connection =

               new SqlConnection(connectionString))

    {

        SqlDataAdapter dataAdpater = new SqlDataAdapter(

          "SELECT CategoryID, CategoryName FROM Categories",

          connection);

        dataAdpater.UpdateCommand = new SqlCommand(

           "UPDATE Categories SET CategoryName = @CategoryName " +

           "WHERE CategoryID = @CategoryID", connection);

        dataAdpater.UpdateCommand.Parameters.Add(

           "@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

        SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(

          "@CategoryID", SqlDbType.Int);

        parameter.SourceColumn = "CategoryID";

        parameter.SourceVersion = DataRowVersion.Original;

        DataTable categoryTable = new DataTable();

        dataAdpater.Fill(categoryTable);

        DataRow categoryRow = categoryTable.Rows[0];

        categoryRow["CategoryName"] = "New Beverages";

        dataAdpater.Update(categoryTable);

        Console.WriteLine("Rows after update.");

        foreach (DataRow row in categoryTable.Rows)

        {

            {

                Console.WriteLine("{0}: {1}", row[0], row[1]);

            }

        }

    }

}


       

原创粉丝点击