将当前行从 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
将保存每一种变化;编辑、删除和插入(新行)
我应该创建一个主从表单,我必须直接在绑定到数据库的 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
)、
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
将保存每一种变化;编辑、删除和插入(新行)