0

レコードのリストを表示する DataGridView があり、挿入ボタンを押すと、フォームは新しいレコードを追加し、その値を編集して保存する必要があります。

DataGridView にバインドされた BindingSource があります。私はパラメータとして NEW RECORD フォームに渡すので、

// When the form opens it add a new row and de DataGridView display this new record at this time
DataRowView currentRow;
currentRow = (DataRowView) myBindindSource.AddNew();

ユーザーがそれを保存することを確認したら、私は

myBindindSource.EndEdit(); // inside the form

フォームが破棄された後、新しい行が保存され、バインディングソースの位置が新しい行に更新されます

DataRowView drv = myForm.CurrentRow;
avaliadoTableAdapter.Update(drv.Row);
avaliadoBindingSource.Position = avaliadoBindingSource.Find("ID", drv.Row.ItemArray[0]);

問題は、このテーブルに AUTOINCREMENT フィールドがあり、保存された値が bindingSource が EDIT TIME で指定した値と一致しない可能性があることです。

そのため、DataGridView を閉じて再度開くと、新しい行は、保存された瞬間に元の DB で使用可能なスロットに基づいて ID を与え、BindingSource が生成した広告の値を無視するだけです EDIT TIME,

バインディング ソースによって指定された値は、別のテーブルで foreingKey として使用される必要があるため、参照が矛盾します。

データベースに保存された実際の ID を取得する方法はありますか?

4

6 に答える 6

2

私はこの解決策を思いつきます

最初に GetNextID() メソッドをテーブル モデルに直接追加しました。

SELECT     autoinc_next
FROM         information_schema.columns
WHERE     (table_name = 'Estagio') AND (column_name = 'ID')

新しい行を追加する必要があるときは、そうします

 EstagioTableAdapter ta = new EstagioTableAdapter ();
 nextID = ta.GetNextID();

 row = (DataRowView)source.AddNew();
 row.Row["ID"] = nextID;
 (...)
 source.EndEdit();
于 2010-01-02T23:12:02.787 に答える
0

注: SQLiteConnection と SQLiteDataAdapter を MSSQL のものに変更し、LAST_INSERT_ROWID() をSCOPE_IDENTITY ( ) に変更するだけです。

RowUpdatedを使用します(複数ステートメントをサポートしないSQLCEおよび RDBMS で動作します):

const string devMachine = @"Data Source=C:\_DEVELOPMENT\__.NET\dotNetSnippets\Mine\TestSqlite\test.s3db";

SQLiteConnection c = new SQLiteConnection(devMachine);
SQLiteDataAdapter da = new SQLiteDataAdapter();
DataTable dt = new DataTable();

public Form1()
{
    InitializeComponent();


    da = new SQLiteDataAdapter("select product_id, product_name, abbrev from product", c);

    var b = new SQLiteCommandBuilder(da);

    da.InsertCommand = b.GetInsertCommand();
    da.UpdateCommand = b.GetUpdateCommand();
    da.DeleteCommand = b.GetDeleteCommand();

    da.Fill(dt);


    da.RowUpdated += da_RowUpdated;


    bds.DataSource = dt;
    grd.DataSource = bds;



}

void da_RowUpdated(object sender, System.Data.Common.RowUpdatedEventArgs e)
{
    if (e.StatementType == StatementType.Insert)
    {
        int ident = (int)(long) new SQLiteCommand("select last_insert_rowid()", c).ExecuteScalar();
        e.Row["product_id"] = ident;
    }
}

private void uxUpdate_Click(object sender, EventArgs e)
{
    da.Update(dt);
}
于 2009-11-19T06:09:04.120 に答える
0

SQLiteConnection クラスを使用する機会はありませんでしたが、SQLConnection および SQLCommand クラスを使用しました。SqlCommand には、t-sql ステートメントの最初の行と最初の列の値を返すメソッド ExecuteScalar があります。これを使用して、Auto-Identity 列を返すことができます。また、SQL Server 2005 には OUTPUT という名前のキーワードがあります。これもチェックしてください。

于 2009-11-19T06:58:44.130 に答える
0

同時実行違反に関する私の回答に基づいて、da.InsertCommand を使用します。UpdatedRowSource = UpdateRowSource.FirstReturnedRecord.

注: SQLiteConnection と SQLiteDataAdapter を MSSQL のものに変更し、LAST_INSERT_ROWID() をSCOPE_IDENTITY ( ) に変更するだけです。

    const string devMachine = @"Data Source=C:\_DEVELOPMENT\__.NET\dotNetSnippets\Mine\TestSqlite\test.s3db";

    SQLiteConnection c = new SQLiteConnection(devMachine);
    SQLiteDataAdapter da = new SQLiteDataAdapter();
    DataTable dt = new DataTable();

    public Form1()
    {
        InitializeComponent();


        da = new SQLiteDataAdapter("select product_id, product_name, abbrev from product", c);

        var b = new SQLiteCommandBuilder(da);

        da.InsertCommand = new SQLiteCommand(
            @"insert into product(product_id, product_name, abbrev) values(:_product_id, :_product_name, :_abbrev);
            select product_id /* include rowversion field here if you need */ 
            from product where product_id = LAST_INSERT_ROWID();", c);
        da.InsertCommand.Parameters.Add("_product_id", DbType.Int32,0,"product_id");
        da.InsertCommand.Parameters.Add("_product_name", DbType.String, 0, "product_name");
        da.InsertCommand.Parameters.Add("_abbrev", DbType.String, 0, "abbrev");
        da.InsertCommand.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord;

        da.UpdateCommand = b.GetUpdateCommand();
        da.DeleteCommand = b.GetDeleteCommand();

        da.Fill(dt);


        bds.DataSource = dt;
        grd.DataSource = bds;

    }

    private void uxUpdate_Click(object sender, EventArgs e)
    {
        da.Update(dt);
    }

SQLite のサンプル テーブルは次のとおりです。

CREATE TABLE [product] (
[product_id] INTEGER  NOT NULL PRIMARY KEY AUTOINCREMENT,
[product_name] TEXT  NOT NULL,
[abbrev] TEXT  NOT NULL
)

[2009 年 11 月 19 日 12:58 PM CN 編集]うーん...私の答えは使用できないと思います。SQLCE では複数のステートメントが許可されていません

とにかく、サーバーベースのMSSQLを使用する場合、またはSQLiteを使用する場合は、私の答えを使用してください. または、おそらく、2 つのステートメントを scope_identity(integer) を返す関数にカプセル化します。

da.InsertCommand = new SQLiteCommand(
@"select insert_to_product(:_product_id, :_product_name, :_abbrev) as product_id", c);
da.InsertCommand.Parameters.Add("_product_id", DbType.Int32,0,"product_id");
da.InsertCommand.Parameters.Add("_product_name", DbType.String, 0, "product_name");
da.InsertCommand.Parameters.Add("_abbrev", DbType.String, 0, "abbrev");
da.InsertCommand.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord;
于 2009-11-19T04:50:47.290 に答える
0

私はこれに出くわしました:あなたがする必要があるのは、自動インクリメントシードを-1に設定し、それを-1だけ「インクリメント」することだけです。このようにして、すべてのデータ行に、実際のデータベースのどこにもマップされない一意の ID が割り当てられます。を使用してデータを保存している場合はDataAdapter、保存後にデータ行と、その ID を指すデータ関係を持つ他の行が更新されます。

于 2009-11-24T13:11:50.123 に答える
0

Access データベースでも同じことが起こります。ここに素晴らしい記事(解決策付き)があります。基本的に、TableAdapter は通常、データを保存するときに 2 つのクエリをバッチで送信します。1 つ目はデータを保存し、2 つ目は新しい ID を要求します。残念ながら、Access も SQL CE もバッチ ステートメントをサポートしていません。

解決策は、DB に新しい ID を照会する RowUpdated のイベント ハンドラーを追加することです。

于 2009-11-19T03:22:52.507 に答える