开发者

BindingSource sees changes, DataTable doesn't

I have recently switched over from Java/RMI to C# / .net, and am working on my first project using databinding to update records in Oracle. On this first form I'm building, I have a detail view for vehicle records (VIN, year/make/model, license plate number, that sort of thing). The first thing I did in terms of writing to the DB was saving updates:

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.");
        }
    }
}

That all seemed ok, so I moved on to adding new records. I made a button (I saw online where various people had said it was as good or better to make your own than use a binding navigator) and put this in its handler:

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;

So there (above) I'm putting initial values into some required columns (VEH_ID is the PK). Then I ran the app, entered a value in the textbox for VIN, and went to save (same code as above) and this time GetChanges() returned null.

So I tried this in the "add new" button handler, in place of the first thing:

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;

Now I have something really interesting happening.

- I can successfully enter and save data on any number of new records, until I select an existing record. If I move to an existing record and then add a new record, then when I go to save the new record, the values that were explicitly set in code get written to the DB but data entered into the GUI do not "take" for the new record.

- I can successfully change any number of existing records, until I enter a new record. If I add one or more new records, save, and then try to save changes to an existing record, the call to GetChanges() returns null (so again, apparently it is not "seeing" what's been entered through the GUI).

So in both of these cases, the change from old to new, or new to old, appears to introduce some condition that makes the datatable unaware of what was entered into the GUI. But in changing from old to new it only takes selecting an existing record, whereas with changing from new to old, it only breaks after saving (if I do a new record but then abandon it without saving, I can modify existing records without problems).

I added this into the save handler, just prior to the actual save (in a loop because ch is a datatable, but really the code is set up to where you have to either save or abandon the new record before moving on - thus the loop only executes once):

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 + "'");
}

Where VIN_ID is the column to which this particular textbox is bound (I tried this with other fields on the form too, to verify it wasn't just something flaky about that one textbox). The first message box (DataRowView from the binding source) shows the vin that I entered into the textbox. The second message box (row from the table returned by GetChanges()) shows the empty string for VIN_ID, although it has the correct (set through code) values for VEH_ID and GRNTE_ID. The same thing happens if I select a different value for GRNTE_ID using the combo box bound to that column; the row from the datatable still has the value that was set through code, "unaware" of the value selected through the GUI.

Why would the datatable and binding source have different values for the same field? And why would the datatable be able to "see" values entered through the GUI only until the user switches from existing to new, or from new to existing?

Thanks.


Angel: I'm doing that in my Service:

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; 
} 

This is called from this block from my original post:

Service<TVDDataService.IService1>.Use(svcProxy => 
{ 
    isSaved = svcProxy.SaveVehicles(ch); 
}); 

Johannes:

The call to EndEdit() is the second line in the save handler (near the top of my post). Should I be calling it somewhere else as well?

Thanks.


Just to clarify: SaveVehicles cannot be the source of the problem, since the problem is appearing before SaveVehicles is ever called. What condition could cause a discrepancy between the BindingSource and the DataTable after EndEdit() has been called and before anything actually writes to the DB?


You have to update your table adapter after use EndEdit(); also you can update your complete DataSet with the follow snippet :

            this.BindingSource1.EndEdit();
            this.TableAdapter1.Update(this.DataSet1);

Hopes Helps...


*IF you are using a BindingSource as well: Just do a simple BindingSource.EndEdit() and your TextBox data will be sent over to the DataTable. Example:-

_bsHeader.EndEdit();
if (_dsHeader.HasChanges())
{
DataTable dsInsert = _dsHeader.GetChanges(DataRowState.Added).Copy();
_objDal.Insert(dsInsert);
}

Hope this helps anyone who stumbles here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜