Search code examples
c#linq-to-sqlunique-index

SqlException when inserting multiple records table with unique index in linq-sql


I have a sql table with a PK column ItemID and unique index on column 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
)

I'm inserting multiple records (batch insert/update) in the table using linq-sql. I do an "exists" check before inserting the record.

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();
    }
}

I get the below exception due to the unique index if the list has the same values. Item table has no records.

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

Exception message:

Cannot insert duplicate key row in object 'dbo.Item' with unique index 'IDX_Item_Value_U_NC'.
The statement has been terminated.

How do I avoid this?

EDIT: I cannot do single inserts so I cannot move the db.SubmitChanges() call inside the for loop.

EDIT2: The answers posted so far deal with fixing the data rather than a way within linq-sql. I have put a simple example with a list of ints. But in reality I have a list of object graph to inserts and every item hits multiple tables for insert/update. I found a way using linq DataContext's ChangeSet (DataContext.GetChangeSet().Deletes, DataContext.GetChangeSet().Inserts, etc.) which I have posted as answer.


Solution

  • The problem here is that you are inserting them both at the same time. Neither of them exist until you actually call db.SubmitChanges()

    Try moving the db.SubmitChanges() inside the loop and that should solve the problem.

    ETA: Another possibility would be changing your loop from:

    foreach (var value in values)
    

    to

    foreach (var value in values.Distinct())