DataSet 的 Merge()

ADO .NET 中我们在合并两个相同或相近的 DataSet 对象时,通常会使用 DataSet Merge 方法,该方法有多个重载版本,在介绍它之前我们先复习 Merge 方法,以下是 MSDN 中对 Merge 方法使用说明 :

Merge 方法用于合并架构大致相似的两个 DataSet 对象。合并在客户端应用程序上通常用于将数据源中最近的更改合并到现有的 DataSet 中。这使客户端应用程序能够拥有用数据源中的最新数据刷新的 DataSet 。通常在一系列过程的末尾调用 Merge 方法,这些过程涉及验证更改、消除错误、使用更改更新数据源并最后刷新现有的 DataSet
在客户端应用程序中,通常有这样一个按钮,用户可以单击它来收集已更改的数据并对其进行验证,然后将其发送回中间层组件。在这种情况下,将首先调用 GetChanges 方法。该方法返回另一个为验证和合并而优化的 DataSet 。第二个 DataSet 对象只包含已更改的 DataTable DataRow 对象,结果产生初始 DataSet 的子集。该子集通常较小,因此可以更有效率地传递回中间层组件。然后,中间层组件将通过存储过程使用更改更新初始数据源。然后,中间层可以发送回一个新的 DataSet ,其中包含数据源中的初始数据和最新数据(通过再次运行初始查询);或者它可以发送回包含从数据源对其进行的所有更改的子集。(例如,如果数据源自动创建唯一主键值,则可以将这些值传播回客户端应用程序。)在哪一种情况下都可以使用 Merge 方法将返回的 DataSet 合并回客户端应用程序的初始 DataSet
当将新的源 DataSet 合并到目标中时, DataRowState 值为 Unchanged Modified Deleted 的任何源行都会与具有同一主键值的目标行相匹配。 DataRowState 值为 Added 的源行将匹配主键值与新源行相同的新目标行。
根据以上说明,我们知道 Merge 方法在合并两个数据集时,是以行的主键值为主要对比参照。这样在向数据集添加新行时不会有任何问题,在修改了行且不修改主键值的情况下也不会有问题,但是在更改行时如果你修改了主键的值,那问题就来了 …… 下面我们就举例说明:
SQL Server 下的一个 Products 表结构如下:
列名
数据类型
说明
Code
nchar
产品代码 ( 主键列 )
Name
nvarchar
产名名称
UnitPrice
numeric
产品单价
.NET 中使用 XSD 生成一个对应的 ProductsData.xsd 结构如下:
列名
数据类型
说明
Code
string
产品代码 ( 主键列 )
Name
string
产名名称
UnitPrice
decimal
产品单价
根据 MSDN 的说明,我们在前台通过 ProductsData 添加或修改数据后在提交后台更新时,通常做法如下:
        // 创建一个新数据集来保存对主数据集所做的更改
        ProductsData dataSetChanges;
        dataSetChanges = (ProductsData)(productsData.GetChanges());
        // 检查是否做了任何更改
        if(dataSetChanges != null) {
            try {
                // 需要做一些更改,所以尝试通过调用 update 方法
// 和传递数据集以及任何参数来更新数据源
                UpdateDataSource(dataSetChanges);
                productsData.Merge(dataSetChanges);
                productsData.AcceptChanges();
            }
            catch (System.Exception eUpdate) {
                throw eUpdate;
            }
        }
以上代码是根据 VS.NET 的数据窗体生成向导写的,依据以上代码我们模拟向数据集添加一行数据并更新后的情况:
Code
Name
UnitPrice
1001
金砂朱古力
120.00
没问题,下面我们修改这行数据再更新,这里我们把 Code 改为 1002 ,更新之后结果数据并没有按我们预想的把原本行 Code 列的值 1001 改为 1002 ,而是添加了一行:
Code
Name
UnitPrice
1001
金砂朱古力
120.00
1002
金砂朱古力
130.00
注:通常情况下我们是很少更改主键值,但在代码没有被使用的情况下,一般是允许更改 Code 的,特别是在系统实施的阶段。
出现以上问题的原因其实不奇怪,按 Merge 方法的原理,这一点也没错,但这是我们不希望的结果,怎么解决呢,难道不允许用户更改主键,但好象不符合实际。怎么解决呢?
既然要用 Merge 方法,那只有依 Merge 合并数据的原理去做,不让改主键我们就不改主键,我们可以给前台的 ProductsData 的数据集加多一个额外的主键 ID 列,并把它的 AutoIncrement 设为 true ,将原本的主键列 Code 改为 Key 列,至于后台 SQL Server 中的源表不作任何修改,修改后如下:
列名
数据类型
说明
ID
Int
自动增长列 (主键)
Code
String
产品代码   ( key 键)
Name
String
产名名称
UnitPrice
decimal
产品单价
经这样一改,由于 ID 是自动一个自递增列,我们并不去修改它的值,这样我们就可以随意更改 Code 列的值了, Merge 方法在合并数据时由于是依据ID例进行比对所以也不会再出现前面加多一行的问题了。

 


 

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


namespace  test1
{
    
class Program
    
{
        
static void Main(string[] args)
        
{
            test ts 
= new test();
            ts.DemonstrateMergeTableAddSchema();
        }


    }


    
class test
    
{

        
public void DemonstrateMergeTableAddSchema()
        
{
            
// Create a DataSet with one table, two columns, and ten rows.
            DataSet dataSet = new DataSet("dataSet");
            DataTable table 
= new DataTable("Items");

            
// Add table to the DataSet
            dataSet.Tables.Add(table);

            
// Create and add two columns to the DataTable
            DataColumn idColumn = new DataColumn("id",
                Type.GetType(
"System.Int32"), "");
            idColumn.AutoIncrement 
= true;
            DataColumn itemColumn 
= new DataColumn("Item",
                Type.GetType(
"System.Int32"), "");
            table.Columns.Add(idColumn);
            table.Columns.Add(itemColumn);

            
// Set the primary key to the first column.
            table.PrimaryKey = new DataColumn[1{ idColumn };

            
// Add RowChanged event handler for the table.
      
//  table.RowChanged += new DataRowChangeEventHandler(Row_Changed);


            
// Add ten rows.
            for (int i = 0; i < 10; i++)
            
{
                DataRow row 
= table.NewRow();
                row[
"Item"= i;
                table.Rows.Add(row);
            }


            
// Accept changes.
           
        dataSet.AcceptChanges();
            DataRow dr 
= table.NewRow();
            dr[
1= "5555";
            table.Rows.Add(dr);           


          table.Rows[
9][1= "99";

          
// table.Rows[4].Delete();
          
//  table.Rows[10].Delete();




           PrintValues(dataSet, 
"Original values");
            Console.WriteLine(
"-------- ");

            
// Create a second DataTable identical to the first, with
            
// one extra column using the Clone method.
            DataTable cloneTable = table.Clone();
           cloneTable.Columns.Add(
"extra"typeof(string));

            
// Add two rows. Note that the id column can'table be the 
            
// same as existing rows in the DataSet table.
            DataRow newRow;
            newRow 
= cloneTable.NewRow();
            newRow[
"id"= 4;
            newRow[
"Item"= 555;
            newRow[
"extra"= "extra Column 1";
            cloneTable.Rows.Add(newRow);

            newRow 
= cloneTable.NewRow();
            newRow[
"id"= 10;
            newRow[
"Item"= 665;
            newRow[
"extra"= "extra Column 2";
            cloneTable.Rows.Add(newRow);


            newRow 
= cloneTable.NewRow();
            newRow[
"id"= 9;
            newRow[
"Item"= 959;
            newRow[
"extra"= "extra Column 4";
            cloneTable.Rows.Add(newRow);


            newRow 
= cloneTable.NewRow();
            newRow[
"id"= 14;
            newRow[
"Item"= 777;
            newRow[
"extra"= "extra Column 3";
            cloneTable.Rows.Add(newRow);


            
//cloneTable.Rows[0][1] = "4";
            
//cloneTable.Rows[1][1] = "88781";
            
//cloneTable.Rows[2][1] = "88782";
            
//cloneTable.Rows[3][1] = "88783";
         
              
// cloneTable.AcceptChanges();
         
// cloneTable.Rows[0].Delete();
         
// cloneTable.Rows[1].Delete();
          
//cloneTable.Rows[2].Delete();
         
// cloneTable.Rows[0].Delete();



            Console.WriteLine(
"TableName: " + cloneTable.TableName);
            
foreach (DataRow row in cloneTable.Rows)
            
{
                
foreach (DataColumn column in cloneTable.Columns)
                
{
                    Console.Write(
" able " + row[column]);
                }

                Console.Write(
"  ---- " + row.RowState);

                Console.WriteLine();
            }



         
            
// Merge the table into the DataSet.
            Console.WriteLine("Merging");
            dataSet.Merge(cloneTable,
true, MissingSchemaAction.Add);
           
//table.AcceptChanges();
            PrintValues(dataSet, "Merged With Table, Schema Added");
        }


        
private void Row_Changed(object sender,
            DataRowChangeEventArgs e)
        
{
            Console.WriteLine(
"Row Changed " + e.Action.ToString()
                
+ " able" + e.Row.ItemArray[0]);
        }


        
private void PrintValues(DataSet dataSet, string label)
        
{
            Console.WriteLine(
" " + label);
            
foreach (DataTable table in dataSet.Tables)
            
{
                Console.WriteLine(
"TableName: " + table.TableName);
                
foreach (DataRow row in table.Rows)
                
{
                    
foreach (DataColumn column in table.Columns)
                    
{
                        Console.Write(
" able " + row[column]);
                    }

                    Console.Write(
"  ---- " + row.RowState);

                    Console.WriteLine();
                }

            }

        }



    }


}

 

dataSet.Merge(cloneTable,false, MissingSchemaAction.Add);

数据为cloneTable的数据.

 当Table字段为 Unchanged. 
   cloneTable 为 Unchanged  Merge 后 Unchanged 

 当Table字段为 Modified ,Added,Deleted 
   cloneTable 为 Unchanged  Merge 后 Modified

----------------------------------------------------------

 当Table字段为 Modified,Unchanged,Deleted
   cloneTable 为 Added  Merge 后 Modified

 当Table字段为 Added
   cloneTable 为 Added  Merge 后 Added

---------------------------------------------------------

 当Table字段为 Modified,Unchanged,Deleted,Added
   cloneTable 为 Deleted  Merge 后 Deleted
   cloneTable 为 Modified Merge 后 Modified


 

 dataSet.Merge(cloneTable,true, MissingSchemaAction.Add);

数据为Table的数据.

 当Table字段为 Modified ,Added,Unchanged 
   cloneTable 为 Unchanged  Merge 后 Modified

 当Table字段为 Deleted 
   cloneTable 为 Unchanged  Merge 后 Deleted 

----------------------------------------------------------

 当Table字段为 Modified,Unchanged,
   cloneTable 为 Added  Merge 后 Modified

 当Table字段为 Added
   cloneTable 为 Added  Merge 后 Added

 当Table字段为 Deleted 
   cloneTable 为 Added  Merge 后 Deleted 

---------------------------------------------------------

 当Table字段为 Modified,Unchanged,Added
   cloneTable 为 Deleted  Merge 后 Modified
   cloneTable 为 Modified Merge 后 Modified

 当Table字段为 Deleted 
   cloneTable 为 Modified,Deleted  Merge 后 Deleted 
-----------------------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值