我最近从Java / RMI切换到C#/ .net,正在使用数据绑定来更新Oracle中的记录。在我正在构建的第一个表格中,我有车辆记录的详细视图(VIN,年份/品牌/型号,车牌号码,那种东西)。我在写入数据库方面做的第一件事就是保存更新:
private void btn_saveDesc_Click(object sender, EventArgs e)
{
bool isSaved = false;
hJA_VEHICLEBindingSource.EndEdit();
DataSet1.HJA_VEHICLEDataTable ch =
(DataSet1.HJA_VEHICLEDataTable)dataSet1.HJA_VEHICLE.GetChanges();
if (ch == null)
{
MessageBox.Show("There are no changes to save.");
}
else
{
Service<TVDDataService.IService1>.Use(svcProxy =>
{
isSaved = svcProxy.SaveVehicles(ch);
});
if (isSaved)
{
// update the vehicle in the local dataset
var modifiedRows = from row in dataSet1.HJA_VEHICLE
where row.RowState == DataRowState.Modified
select row;
foreach (DataRow row in modifiedRows)
{
row.Delete();
}
dataSet1.HJA_VEHICLE.Merge(ch);
dataSet1.HJA_VEHICLE.AcceptChanges();
}
if(isSaved)
{
MessageBox.Show("The record has been saved.");
}
else
{
MessageBox.Show("The record could not be saved.");
}
}
}
一切似乎都没问题,所以我继续添加新记录。我做了一个按钮(我在网上看到各种各样的人说自己做的比使用绑定导航器更好或更好)并把它放在它的处理程序中:
DataRowView drv = (DataRowView)hJA_VEHICLEBindingSource.AddNew();
currVeh_id = nextID(); // generate arbitrary ID for the record
drv["VEH_ID"] = currVeh_id;
drv["GRNTE_ID"] = lastSelectedGranteeID; // just to have an initial value
hJA_VEHICLEBindingSource.Filter = "VEH_ID = " + currVeh_id;
所以(上面)我将初始值放入一些必需的列(VEH_ID是PK)。然后我运行应用程序,在VIN的文本框中输入一个值,然后去保存(与上面相同的代码),这次GetChanges()返回null。
所以我在“添加新”按钮处理程序中尝试了这个,取代了第一件事:
DataSet1.HJA_VEHICLERow newRow =
(DataSet1.HJA_VEHICLERow)dataSet1.HJA_VEHICLE.NewRow();
currVeh_id = nextID();
newRow.VEH_ID = currVeh_id;
newRow.GRNTE_ID = lastSelectedGranteeID;
dataSet1.HJA_VEHICLE.AddHJA_VEHICLERow(newRow);
hJA_VEHICLEBindingSource.Filter = "VEH_ID = " + currVeh_id;
现在我发生了一些非常有趣的事情 - 我可以成功输入并保存任意数量的新记录数据,直到我选择现有记录。如果我移动到现有记录然后添加新记录,那么当我去保存新记录时,代码中显式设置的值将被写入数据库,但输入GUI的数据不会“获取”新记录 - 我可以成功更改任意数量的现有记录,直到我输入新记录。如果我添加一个或多个新记录,保存,然后尝试将更改保存到现有记录,则对GetChanges()的调用将返回null(因此,显然它不会“看到”通过GUI输入的内容)。 / p>
因此,在这两种情况下,从旧到新,或从新到旧的变化似乎都会引入一些条件,使数据表不知道输入GUI的内容。但是在从旧到新的变换中它只需要选择一个现有的记录,而从新到旧的变化,它只会在保存后中断(如果我做了一个新的记录但是放弃它而不保存,我可以毫无问题地修改现有的记录)
我将它添加到保存处理程序中,就在实际保存之前(在循环中因为ch是一个数据表,但实际上代码设置为在继续之前必须保存或放弃新记录的位置 - 因此循环只执行一次):
foreach (DataSet1.HJA_VEHICLERow r in ch)
{
DataRowView drv = (DataRowView)hJA_VEHICLEBindingSource.Current;
MessageBox.Show(drv["VIN_ID"].ToString());
MessageBox.Show(r.VEH_ID + "\n" + r.GRNTE_ID + "\n'"
+ r.VIN_ID + "'");
}
其中VIN_ID
是此特定文本框绑定到的列(我也尝试使用表单上的其他字段,以验证它不仅仅是关于该文本框的一些内容)。第一个消息框(来自绑定源的DataRowView)显示我在文本框中输入的vin。第二个消息框(GetChanges()返回的表中的行)显示VIN_ID
的空字符串,尽管它具有VEH_ID
和GRNTE_ID
的正确(通过代码设置)值。如果我使用绑定到该列的组合框为GRNTE_ID
选择不同的值,则会发生同样的事情;数据表中的行仍然具有通过代码设置的值,“不知道”通过GUI选择的值。
为什么数据表和绑定源对同一个字段有不同的值?为什么数据表能够“看到”通过GUI输入的值,直到用户从现有切换到新,或从新切换到现有?
感谢。
天使: 我在我的服务中这样做:
public bool SaveVehicles(DataSet1.HJA_VEHICLEDataTable vehicles)
{
bool saved = false;
if (vehicles != null && !vehicles.HasErrors)
{
HJA_VEHICLETableAdapter ta = new HJA_VEHICLETableAdapter();
int result = ta.Update(vehicles);
saved = (result > 0);
}
return saved;
}
这是从我原来的帖子中调用的:
Service<TVDDataService.IService1>.Use(svcProxy =>
{
isSaved = svcProxy.SaveVehicles(ch);
});
约翰内斯:
对EndEdit()的调用是保存处理程序中的第二行(靠近帖子的顶部)。我应该在别的地方打电话吗?
感谢。
只是为了澄清:SaveVehicles不能成为问题的根源,因为问题出现在调用SaveVehicles之前。在调用EndEdit()之后以及在实际写入数据库的任何内容之前,什么条件可能导致BindingSource和DataTable 之间的差异?
答案 0 :(得分:1)
使用EndEdit()后,您必须更新表适配器;您还可以使用以下代码段更新完整的DataSet:
this.BindingSource1.EndEdit();
this.TableAdapter1.Update(this.DataSet1);
希望有助于......
答案 1 :(得分:0)
*如果您正在使用BindingSource: 只需执行一个简单的BindingSource.EndEdit(),您的TextBox数据就会被发送到DataTable。 例如: -
_bsHeader.EndEdit();
if (_dsHeader.HasChanges())
{
DataTable dsInsert = _dsHeader.GetChanges(DataRowState.Added).Copy();
_objDal.Insert(dsInsert);
}
希望这有助于任何在这里绊倒的人。