1

私は最近、Java/RMI から C#/.net に切り替え、データバインディングを使用して Oracle のレコードを更新する最初のプロジェクトに取り組んでいます。私が作成しているこの最初のフォームには、車両記録 (VIN、年/メーカー/モデル、ナンバー プレート番号など) の詳細ビューがあります。DB への書き込みに関して最初にしたことは、更新を保存することでした。

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;

今、私は本当に興味深いことが起こっています。
- 既存のレコードを選択するまで、新しいレコードのデータをいくつでも正常に入力して保存できます。既存のレコードに移動してから新しいレコードを追加すると、新しいレコードを保存するときに、コードで明示的に設定された値が DB に書き込まれますが、GUI に入力されたデータは、新記録。
- 新しいレコードを入力するまで、既存のレコードをいくつでも変更できます。1 つまたは複数の新しいレコードを追加して保存し、既存のレコードに変更を保存しようとすると、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(フォームの他のフィールドでもこれを試して、その 1 つのテキストボックスについて不安定なものではないことを確認しました)。最初のメッセージ ボックス (バインディング ソースの DataRowView) には、テキスト ボックスに入力した vin が表示されます。2 番目のメッセージ ボックス (GetChanges() によって返されるテーブルの行)VIN_IDには、 と の正しい (コードによって設定された) 値がVEH_IDありますが、 の空の文字列が表示されますGRNTE_IDGRNTE_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() の呼び出しは、保存ハンドラーの 2 行目 (私の投稿の上部近く) です。私はそれを別の場所でも呼び出す必要がありますか?

ありがとう。


明確にするために: SaveVehicles が呼び出される前に問題が発生しているため、SaveVehicles が問題の原因になることはありません。EndEdit() が呼び出された後、実際に DB に何かが書き込まれる前に、BindingSource と DataTable の間で不一致が生じる可能性があるのはどのような条件ですか?

4

2 に答える 2

1

EndEdit()を使用した後は、テーブルアダプタを更新する必要があります。また、次のスニペットを使用して完全なデータセットを更新できます。

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

助けてくれることを願っています...

于 2009-11-02T21:27:57.383 に答える
0

* BindingSource も使用している場合: シンプルな BindingSource.EndEdit() を実行するだけで、TextBox データが DataTable に送信されます。例:-

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

これがここでつまずいた人の助けになることを願っています。

于 2013-03-13T08:13:28.993 に答える