【发布时间】:2009-11-02 21:19:49
【问题描述】:
我最近从 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 输入的内容)。
因此,在这两种情况下,从旧到新或从新到旧的变化似乎会引入一些条件,使数据表不知道输入到 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 之间出现差异?
【问题讨论】:
标签: c# data-binding bindingsource