zoukankan      html  css  js  c++  java
  • DataSet / BindingSource / DataGridView / BindingNavigator 的关系与绑定、修改数据库

    一、说明

    1.数据源DataSet是保存数据,以及发布数据更新通知的核心。
    2.BindingSource,是控件(DataGridView / BindingNavigator)与数据源交互的桥梁。BindingSource的DataSource指向数据源DataSet之后,数据源或控件的数据更改,则会被BindingSource传递到另一头。
    3.DataGridView / BindingNavigator是数据控件,它们应该从BindingSource获取数据。当数据控件的数据,被用户更改后,则会通知BindingSource,接着BindingSource再通知数据源DataSet。

    因此,这些组件绑定与更新的顺序为:

    1.创建DataSet
    2.把BindingSource的BindingSource绑定到DataSet。
    3.把DataGridView的DataSource,以及BindingNavigator的BindingSource,都绑定到BindingSource。
    关键:如果DataSet的数据发生变化,或者DataGridView / DataSource的数据发生变化,则双向的更改是自动进行与传递的。
    但如果DataSet被替换,则需要把BindingSource的BindingSource重新绑定到DataSet。DataGridView 与 BindingNavigator则不需要更改,因为BindingSource会自动通知他们。
    同理,如果DataGridView的DataSource,以及BindingNavigator的BindingSource被替换,也就是他们的BindingSource被替换,则DataSet也需要重新绑定到新的BindingSource中。注意,DataGridView的DataSource,以及BindingNavigator的BindingSource,应该被替换为同一个BindingSource,这样他们才能具有可交互性。

    二、例子

     代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;
    
    namespace WindowsFormsApplication4
    {
        public partial class Form1 : Form
        {
            DataSet ds = new DataSet();
            string conn = "Data Source = (local)\SQLEXPRESS; Initial Catalog = northwind; Persist Security Info = True;User ID=sa;Password=6617saSA";
            string sql = "SELECT CustomerID  编号,CompanyName  ,ContactName ,ContactTitle  ,Address ,City  FROM Customers ;";
            SqlDataAdapter sda ;
            BindingSource bindingsource1 ;
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                dataGridView1.AllowUserToAddRows = false; //去掉DataGridView的最后一个空行
                bindingsource1 = new BindingSource();
                sda = new SqlDataAdapter(sql, conn);
                sda.Fill(ds, "Customers");    
                bindingsource1.DataSource = ds;
                bindingsource1.DataMember = ds.Tables[0].TableName;
                bindingNavigator1.BindingSource = bindingsource1;
                dataGridView1.DataSource = bindingsource1;
    
                //textBox_ID.DataBindings.Add("text", bs, "编号",false, DataSourceUpdateMode.OnPropertyChanged);
                //textBox_name.DataBindings.Add("text", bs, "CompanyName", false, DataSourceUpdateMode.OnPropertyChanged);
                textBox_ID.DataBindings.Add("text", bindingsource1, "编号");
                textBox_name.DataBindings.Add("text", bindingsource1, "CompanyName");
    
                textBox_ContactName.DataBindings.Add("text", bindingsource1, "ContactName");
                textBox_ContactTitle.DataBindings.Add("text", bindingsource1, "ContactTitle");
                textBox_Address.DataBindings.Add("text", bindingsource1, "Address");
                textBox_City.DataBindings.Add("text", bindingsource1, "City");
            }
    
            private void toolStripButton1_Click(object sender, EventArgs e)
            {
                //该语句使修改cell内容后直接保存有效,否则需要移动到其它CELL再保存才有效
                dataGridView1.CurrentCell = null; 
                //将控制修改内容更新到DataSet基础数据,如果没有EndEdit() , ds.GetChanges() == null永远成立
                ((BindingSource)dataGridView1.DataSource).EndEdit();
                if (ds.GetChanges() != null)
                {
                    //没有下一条会出现错误:当传递具有新行的 DataRow 集合时,Update 要求有效的 InsertCommand
                    SqlCommandBuilder sb1 = new SqlCommandBuilder(sda);
                    sda.Update(ds.Tables["Customers"]);//更新数据库
                    ds.AcceptChanges();
                }
            }
    
            private void label2_Click(object sender, EventArgs e)
            {
    
            }
    
            private void textBox_ContactName_TextChanged(object sender, EventArgs e)
            {
    
            }
        }
    }

    三、DataTable的AcceptChange方法为什么不能在Update之前?

    总结:DataTable.AcceptChanges相当于将DataTable表中的所有DataRow的RowState状态 重置为Unchanged

    DataTable.RejectChanges方法:回滚自该表加载以来或者上次调用AcceptChanges以来对该表进行的所有更改;并且DataTable表中的所有DataRow的RowState状态 重置为Unchanged

    例子:

    DataTable dataTable = ds.Tables[0];

    dataTable.Rows[0][0] = 96.6669;//此时的RowState为Modied

    dataTable.AcceptChanges();//此时的RowState为Unchanged

    dataTable.Rows[0][0] = 7777;此时的RowState为Modied此时的RowState为Modied
    dataTable.RejectChanges();//此时的dataTable.Rows[0][0] 为96.6669,RowState为Unchanged

    //最后 Update需要注意的是;防止并发性的操作。有在Update执行之前所包含的数据行有被修改,则会发生并发性操作错误。

    da.Update(dataTable);

    解决并发性办法:

    if (dataTable.GetChanges() != null)
    {
    da.Update(dataTable.GetChanges());
    }

    AcceptChanges方法会将所有改动保存到DataSet或DataTable中,使得所有行的状态都是Unchanged(没有被更改状态)

    而DataAdapter.Update方法在保存数据到数据库表时做过一个检查,即检查表行是否被修改过,如果没被修改过,那么更需将不会执行任何命令,直接跳过本行,开始检查下一行,如此,一个表如果行都是Unchanged状态,那么它就不会被更新到数据库中。

    所以,在更改了DataSet或DataTable后,若想调用DataAdapter.Update方法直接更新数据到数据库,那么你只需要这个Update方法,无需在此前调用一次AcceptChanges方法了。

    Added

    该行已添加到 DataRowCollection 中,AcceptChanges尚未调用。

    Deleted

    该行已通过 DataRow 的 Delete 方法被删除。

    Detached

    该行已被创建,但不属于任何 DataRowCollection。DataRow 在以下情况下立即处于此状态:创建之后添加到集合中之前;或从集合中移除之后。

    Modified

    该行已被修改,AcceptChanges 尚未调用。

    Unchanged

    该行自上次调用 AcceptChanges 以来尚未更改。

    DataTable.AcceptChanges方法:提交自上次调用AcceptChanges以来对该表进行的所有更改。

    调用AcceptChanges时,任何仍处于编辑模式的DataRow对象将成功结束其编辑。DataRowState也发生更改:所有Added和Modified行成为Unchanged;Deleted行被移除。

    在您尝试使用DbDataAdapter.Update方法更新DataSet之后,通常会对DataTable调用AcceptChanges方法。

    DataTable.RejectChanges方法:回滚自该表加载以来或上次调用AcceptChanges以来对该表进行的所有更改。

    调用RejectChanges时,任何仍处于编辑模式的DataRow对象将取消其编辑。新行被移除。DataRowState设置为Modified或Deleted的行返回到其初始状态。

    会出现对DataTable进行多次更改,但是通过调用RejectChanges方法拒绝这些更改的现象

    DataRow.BeginEdit方法:对DataRow对象开始编辑操作。

    使用BeginEdit方法将DataRow置于编辑模式。在此模式中,事件被临时挂起,以便允许用户在不触发验证规则的情况下对多行进行多处更改。例如,如果需要确保总数列的值等于某行中借贷列的值,则可以将每一行都置入编辑模式,以便在用户尝试提交值之前挂起对行值的验证。

    BeginEdit方法在用户更改数据绑定控件的值时被隐式调用;EndEdit方法在您调用DataTable对象的 AcceptChanges方法时被隐式调用。

  • 相关阅读:
    房价
    Jsrender初体验
    GCD XOR UVA
    GCD
    Aladdin and the Flying Carpet LightOJ
    HDU6035 2017多校第一场1003 树形DP
    F
    C
    B
    An Easy Physics Problem HDU
  • 原文地址:https://www.cnblogs.com/wfy680/p/14800559.html
Copyright © 2011-2022 走看看