Я недавно переключился с 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 () вернул ноль.
Итак, я попробовал это в обработчике кнопок «добавить новый», вместо первого:
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;
Теперь у меня происходит кое-что действительно интересное.
- Я могу успешно вводить и сохранять данные о любом количестве новых записей, пока я не выберу существующую запись. Если я перехожу к существующей записи, а затем добавляю новую запись, то при сохранении новой записи значения, которые были явно заданы в коде, записываются в БД, но данные, введенные в графический интерфейс, «не принимают» за Новая запись.
- Я могу успешно изменить любое количество существующих записей, пока не введу новую запись. Если я добавляю одну или несколько новых записей, сохраняю и затем пытаюсь сохранить изменения в существующей записи, вызов 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
, используя поле со списком, привязанное к этому столбцу; строка из таблицы данных по-прежнему имеет значение, которое было установлено с помощью кода, «не известно» о значении, выбранном через графический интерфейс.
Почему источник данных и привязки имеют разные значения для одного и того же поля? И почему объект данных может «видеть» значения, введенные через графический интерфейс, только до тех пор, пока пользователь не переключится с существующего на новое или с нового на существующее?
Спасибо.
Angel:
Я делаю это в моей службе:
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);
});
Johannes:
Вызов EndEdit () - это вторая строка в обработчике сохранения (в верхней части моего сообщения). Должен ли я звонить куда-нибудь еще?
Спасибо.
Просто для пояснения: SaveVehicles не может быть источником проблемы, поскольку проблема появляется до того, как SaveVehicles когда-либо вызывается. Какое условие может вызвать несоответствие между BindingSource и объектом DataTable после вызова EndEdit () и до того, как что-либо действительно записывается в БД?