0

我有一个带有 PK 列ItemID和列上的唯一索引的 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 中的方法。我已经举了一个带有整数列表的简单示例。但实际上我有一个要插入的对象图列表,每个项目都会命中多个表以进行插入/更新。我找到了一种使用 linq (,等)的方法,我已将其发布为答案DataContextChangeSetDataContext.GetChangeSet().DeletesDataContext.GetChangeSet().Inserts

4

3 回答 3

2

这里的问题是您同时插入它们。在您实际调用之前,它们都不存在db.SubmitChanges()

尝试移动db.SubmitChanges()循环内部,这应该可以解决问题。

ETA:另一种可能性是改变你的循环:

foreach (var value in values)

foreach (var value in values.Distinct())
于 2012-08-06T18:36:31.243 回答
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 回答
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 回答