将当前行从 gridview 插入数据库

Insert current row from gridview into database

我应该创建一个主从表单,我必须直接在绑定到数据库的 datagridview 上添加详细信息。所以我有一个包含两个 tables 的表格:intrari(master)和 intrari_detaliu(detail)。 当我使用绑定导航器 select table intrari 中的一行 table 时,我也在 [=] 中获得了相应的详细信息53=]intrari_detaliu。我使用文本 boxes/combox 在 table intrari 中增加价值。 那么如何将值直接插入到数据网格视图中呢? image for the form visual structure

我尝试了什么:

第一次尝试:

   DataClasses1DataContext db = new DataClasses1DataContext();
    private void btnadd_Click(object sender, EventArgs e)
    {
         int ID;  int id_intrari = 0; int id_produs = 0; decimal cantitate = 0; decimal valoare = 0;

         for (int i = 0; i <tbl_intrari_detaliuDataGridView.RowCount - 1; i++)
         {
        if row
             ID = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[0].Value.ToString());
             id_intrari = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[1].Value.ToString());
             id_produs = Convert.ToInt32(tbl_intrari_detaliuDataGridView.Rows[i].Cells[2].Value.ToString());
             cantitate = Convert.ToDecimal(tbl_intrari_detaliuDataGridView.Rows[i].Cells[3].Value.ToString());
             valoare = Convert.ToDecimal(tbl_intrari_detaliuDataGridView.Rows[i].Cells[4].Value.ToString());

             var st = new tbl_intrari_detaliu
             {
                 ID= ID,
                 id_intrari = id_intrari,
                 id_produs = id_produs,
                 cantitate = cantitate,
                 valoare = valoare,
             };
             db.tbl_intrari_detalius.InsertOnSubmit(st);
             db.SubmitChanges();

         }
        
    }

但这首先复制上面的每一行,然后添加新行。例如:我已经插入了A行和B行,当我想插入C行时,它会先插入A行和B行,然后再插入C行。

第二次尝试:

 public partial class Intrari2 : Form

{
    SqlConnection con;
    SqlDataAdapter adap;
    DataSet ds;
    SqlCommandBuilder cmbl;
         private void Intrari2_Load(object sender, EventArgs e)
    {
        con = new SqlConnection();
        con.ConnectionString = @"Data Source=DESKTOP-KVMM566;Initial 
        Catalog=MyDatabase;Integrated Security=True";
        con.Open();
        adap = new SqlDataAdapter("select ID,id_intrari,id_produs,cantitate,valoare from tbl_intrari_detaliu", con);
        ds = new System.Data.DataSet();
        adap.Fill(ds, "tbl_intrari_detaliu");
        tbl_intrari_detaliuDataGridView.DataSource = ds.Tables[0]; 
 this.tbl_intrari_detaliuTableAdapter.Fill(this.myDatabaseDataSet.tbl_intrari_detaliu); 
          this.tbl_IntrariTableAdapter.Fill(this.myDatabaseDataSet.tbl_Intrari);

      //Add button------------
     private void btnadd_Click(object sender, EventArgs e)
    {
        cmbl = new SqlCommandBuilder(adap);
        adap.Update(ds, "tbl_intrari_detaliu");

//the Fill method doesn't work anymore because of the code above
 this.tbl_intrari_detaliuTableAdapter.Fill(this.myDatabaseDataSet.tbl_intrari_detaliu);

   
   }

}

这个更新行正确,但是当我 select 在 table intari 中的一行时,我没有得到相应的详细信息(根据id) 在 table intrari_detaliu 中。我获得了父 table 中所有行的详细信息。我知道这是因为我使用 SqlAdapter 添加到 select 来自 table 的数据的代码,但如果没有该语句,代码将无法工作。

所以,我需要 insert/update/delete 来自“intrari_detaliu”的 selected 行并且当我 select 中的一行时仍然能够获得相应的详细信息父级 table "intrari".

你能帮帮我吗?

比那容易多了。扔掉所有的代码(真的,所有的)。这是一个使用我的两个测试 table 的演示。 1 辆车 (parent) 有很多小丑 (child)


以下是您的数据(应该)进入 parent 网格的方式。您的助教中有一个查询,它根据您要搜索的内容来选择内容,例如姓名:

你给查询起个好名字,而不仅仅是 Fill - 有一天你会有很多查询,不要做 Fill、Fill1、Fill2。现在给他们起个好名字:

在您的 child table 适配器中,您提供了一个通过 Parent ID 进行查找的查询:

或者您执行一个查询,查找 children 与您刚刚 parent 查询相同的东西,例如此处的 CarName:

或者您可以 both/more/whatever。每个 TA 可以有很多查询:


要将网格添加到您的表单中,您需要将它们拖出数据源(查看菜单,其他 Windows)。这将为您完成所有数据绑定设置;如果您想手动复制它,您可以检查 visual studio 是如何完成的; parent 网格通过绑定源绑定到数据集中的 table。 child 网格通过绑定源绑定到 parent 绑定源

上的数据关系

要获得相关数据行为,请将 CHILD NODE Clowns,而不是数据源中的顶级 Clowns 拖出


在您的代码中,要用数据填充网格,您实际上只需填充 tables;网格将自行更新。您必须先填写 parent,然后填写 child。您可以使用根据 parent 条件(例如我的 ...ByCarName)、

选择大量 children 的查询来填充 child
this.carsTableAdapter.FillByCarName(this.dataSet1.Cars, "Billy"); //fill parent first
this.clownsTableAdapter.FillByCarName(this.dataSet1.Clowns, "Billy"); //then fill the children by the same 

或者填完后枚举parent,然后children填parentID(像我的...ByCarId一样):

this.carsTableAdapter.FillByCarName(this.dataSet1.Cars, "Billy"); //fill parent first
clownsTableAdapter.ClearBeforeFill = false; //turn this off otherwise every call to FillBy.. erases the previous rows
foreach (var r in this.dataSet1.Cars) //for each parent
    clownsTableAdapter.FillByCarId(this.dataSet1.Clowns, r.CarId); //fill the children


节省

拖格子这样写:

        this.Validate();
        this.carsBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.dataSet1);

添加一行:

        this.Validate();
        this.carsBindingSource.EndEdit();
        this.clownsBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.dataSet1);

这就是您需要做的;单击运行该代码的按钮; table适配器管理器保存您对数据集所做的任何更改,例如通过在网格底部写入来添加新行...

..或者如果你在代码中这样做:

无论它是如何到达那里的,它都是一个新行,RowState 为 Added

tableadaptermanager.UpdateAll 被呼叫时,或者如果您呼叫个人 tableadapter.Update:

carsTableAdapter.Update(this.dataset1.Cars); //update doesn't just UPDATE, it runs INSERT and DELETE too

然后您在本地所做的更改将被保存。如果其他人在您编辑数据时更改了数据,并且您打开了开放式并发(请参见上面屏幕截图中的“刷新..”),那么您在保存时会遇到异常。您可以选择要执行的操作并编写覆盖新数据、合并数据或丢弃更改的代码;询问用户他们想做什么


请注意,如果数据库正在计算您的 parent 和 child ID 值,请右键单击您的数据 table 之间的关系线,并确保更新设置为级联:

这样当你添加一辆新车和两个新的相关小丑时,这辆车的 ID 为 -1(由数据集在本地生成,pre-save),小丑也使用它:

然后当数据库计算出真实ID时,“刷新数据集”选项...

...导致检索新 ID:

然后将 parent 中的 CarId -1 更改为例如15(DB 的计算结果)导致 child 小丑的 CarId 也自动更新,因此关系得以保留

TableAdapter.Update 将保存每一种变化;编辑、删除和插入(新行)