0

ItemIDPK列と列に一意のインデックスを持つSQLテーブルがありますValue

CREATE TABLE [dbo].[Item](
    [ItemID] [int] IDENTITY(1,1) NOT NULL,
    [Value] [int] NULL
)

CREATE UNIQUE NONCLUSTERED INDEX [IDX_Item_Value_U_NC] ON [dbo].[Item] 
(
    [Value] ASC
)

linq-sqlを使用して、テーブルに複数のレコード(バッチ挿入/更新)を挿入しています。レコードを挿入する前に「存在する」チェックを行います。

void MultipleInserts(List<int> values)
{
    using (var db = new DBDataContext())
    {
        foreach (var value in values)
        {
            var dbItem = db.Items
                    .Where(x => x.Value == value)
                    .SingleOrDefault();

            if (dbItem == null)
            {
                var Item = new Item()
                {
                    Value = value
                };
                db.Items.InsertOnSubmit(Item);
            }
        }
        db.SubmitChanges();
    }
}

リストに同じ値がある場合、一意のインデックスが原因で以下の例外が発生します。Itemテーブルにレコードがありません。

var values = new List<int>();
values.Add(1);
values.Add(1);
MultipleInserts(values);

例外メッセージ:

一意のインデックス「IDX_Item_Value_U_NC」を持つオブジェクト「dbo.Item」に重複するキー行を挿入できません。
ステートメントは終了されました。

これを回避するにはどうすればよいですか?

編集:単一の挿入を実行できないためdb.SubmitChanges()、forループ内で呼び出しを移動できません。

EDIT2:これまでに投稿された回答は、linq-sql内の方法ではなく、データの修正を扱っています。intのリストを使用した簡単な例を示しました。しかし実際には、挿入するオブジェクトグラフのリストがあり、すべてのアイテムが挿入/更新のために複数のテーブルにヒットします。回答として投稿したlinq(、、など)を使用する方法をDataContext見つけましたChangeSetDataContext.GetChangeSet().DeletesDataContext.GetChangeSet().Inserts

4

3 に答える 3

2

ここでの問題は、両方を同時に挿入していることです。実際に電話するまで、どちらも存在しませんdb.SubmitChanges()

ループの内側を動かしてみてくださいdb.SubmitChanges()。そうすれば問題は解決するはずです。

ETA:もう1つの可能性は、ループを次のように変更することです。

foreach (var value in values)

foreach (var value in values.Distinct())
于 2012-08-06T18:36:31.243 に答える
0

これがあなたの質問の単なるタイプミスであったかどうかはわかりませんが、LINQステートメントのWhere句はです.Where(x => x.Value = value)。ここでは、代入ではなく、比較演算子が必要だと思います。LINQステートメントを次のように変更してみてください。

var dbItem = db.Items 
    .Where(x => x.Value == value) 
    .SingleOrDefault();

さらに、.NET 3.5以降を使用している場合は、をに置き換えて、一意の値のみをList<T>持つHashSet<T>ことを保証できます。

于 2012-08-06T18:48:07.253 に答える
0

データを修正するのではなく、DataContextのChangeSetを使用してlinq-sql内で作業する方法を見つけました。この例のデータは単純ですが、複数のテーブルにヒットするオブジェクトグラフである可能性があり、修正が困難です。

最初にをdb.Items調べてから、DataContextのChangeSet(db.GetChangeSet().Inserts)をチェックしてアイテムを見つけ、見つからない場合は挿入します。

void MultipleInserts(List<int> values)
{
    using (var db = new DBDataContext())
    {
        foreach (var value in values)
        {
            // look in db first
            var dbItem = db.Items
                    .Where(x => x.Value == value)
                    .SingleOrDefault();

            if (dbItem == null)
            {
                // look in ChangeSet second
                var cachedItem = db.GetChangeSet().Inserts
                    .OfType<Item>()
                    .Where(x => x.Value == value)
                    .SingleOrDefault();

                if (cachedItem == null)
                {
                    var Item = new Item()
                    {
                        Value = value
                    };
                    db.Items.InsertOnSubmit(Item);
                }
            }
        }
        db.SubmitChanges();
    }
}
于 2012-08-07T17:34:58.733 に答える