C# 在linq sql中插入具有唯一索引的多个记录表时发生SqlException

C# 在linq sql中插入具有唯一索引的多个记录表时发生SqlException,c#,linq-to-sql,unique-index,C#,Linq To Sql,Unique Index,我有一个sql表,其中有一个PK列ItemID,列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在表中插入多条记录(批

我有一个sql表,其中有一个PK列
ItemID
,列
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();
    }
}
异常消息:

无法在具有唯一索引“IDX\U Item\U Value\U\U NC”的对象“dbo.Item”中插入重复的键行。
声明已终止

我如何避免这种情况

编辑:我无法执行单个插入,因此无法在for循环中移动
db.SubmitChanges()
调用


EDIT2:到目前为止,发布的答案涉及修复数据,而不是LINQSQL中的一种方法。我举了一个简单的例子,其中有一个int列表。但实际上,我有一个要插入的对象图列表,每个项目都会命中多个表进行插入/更新。我找到了一种使用linq
DataContext
ChangeSet
DataContext.GetChangeSet().Deletes
DataContext.GetChangeSet().Inserts
,等等)的方法,我已经发布了它们作为答案。

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

尝试在循环中移动
db.SubmitChanges()
,这样应该可以解决问题

ETA:另一种可能是将您的循环更改为:

foreach (var value in values)


我不确定这是否只是您的问题中的一个输入错误,但您的LINQ语句中的Where子句是
。Where(x=>x.Value=Value)
。我想这里需要的是比较运算符,而不是赋值运算符。尝试将LINQ语句更改为以下内容:

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

此外,如果您使用的是.NET 3.5或更高版本,则可以将
列表替换为,以确保只有唯一的值。

我找到了一种使用DataContext的变更集在linq sql中工作的方法,而不是修复数据。示例中的数据很简单,但它可能是一个对象图,它会命中多个表,并且很难修复

我首先查看
db.Items
,然后检查DataContext的变更集(
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();
    }
}
void multipleinsert(列表值)
{
使用(var db=new DBDataContext())
{
foreach(值中的var值)
{
//先查看数据库
var dbItem=db.Items
.其中(x=>x.Value==Value)
.SingleOrDefault();
if(dbItem==null)
{
//第二次查看变更集
var cachedItem=db.GetChangeSet().Inserts
第()类
.其中(x=>x.Value==Value)
.SingleOrDefault();
if(cachedItem==null)
{
变量项=新项()
{
价值=价值
};
db.Items.InsertOnSubmit(项目);
}
}
}
db.SubmitChanges();
}
}

Eric,我理解。我必须做多次插入。我不能做单个插入。@hlpPy-刚刚更新了我的答案。或者,您可以在dbml中将该属性标记为唯一的(虽然已经有一段时间了,但记不清您是如何做到这一点的)我实际上在两列上有一个唯一的索引(我简化了这个问题)。在这种情况下,dbml技巧中的那个独特属性将不起作用。Jon,这是微不足道的-但是
HashSet
是在3.5中引入的。
var dbItem = db.Items 
    .Where(x => x.Value == value) 
    .SingleOrDefault();
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();
    }
}