我需要定期向我的SQL Server数据库中插入一些数据。但是,我读取数据的源重复了之前插入过的一些数据。当我使用Linq-to-SQL插入到数据库中时,会出现数据重复或主键冲突异常,这取决于主键。
如何在不重复且不出现异常的情况下插入数据?我不想用try-catch避免异常,因为一旦异常被引发,其余的数据就无法插入。
更新 我还找到了自己的解决方案:我编写了一个重复条目删除存储过程,在InsertAllOnSubmit + SubmitChanges之后运行。
我需要定期向我的SQL Server数据库中插入一些数据。但是,我读取数据的源重复了之前插入过的一些数据。当我使用Linq-to-SQL插入到数据库中时,会出现数据重复或主键冲突异常,这取决于主键。
如何在不重复且不出现异常的情况下插入数据?我不想用try-catch避免异常,因为一旦异常被引发,其余的数据就无法插入。
更新 我还找到了自己的解决方案:我编写了一个重复条目删除存储过程,在InsertAllOnSubmit + SubmitChanges之后运行。
您只需创建一个新的类实例,然后在表上调用InsertOnSubmit()即可:
var foo = new MyFoo { Name = "foo1" };
var dc = new MyDataContext();
dc.Foos.InsertOnSubmit(foo);
dc.SubmitChanges();
您需要确保的另一件事是如何增加ID列。通常,我总是确保在我的ID列上使用IDENTITY(1,1)设置。在LINQ实体的ID列上声明如下:
[Column(AutoSync = AutoSync.OnInsert, IsPrimaryKey = true, IsDbGenerated = true)]
public Int32 Id { get; set; }
要避免重复项,您真正需要的是我们店里称之为“追加”功能。在我看来,这最容易通过使用存储过程来实现——我们甚至有一个模板用于此:
```USE [<Database_Name, sysobject, Database_Name>]
GO
CREATE PROCEDURE [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>__append]
(
@id INT OUTPUT,
@<Key_Param, sysobject, Key_Param> <Key_Param_Type, sysobject, VARCHAR(50)>
)
AS
BEGIN
SELECT @id = [id] FROM [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s] (NOLOCK) WHERE [<Key_Param, sysobject, Key_Param>] = @<Key_Param, sysobject, Key_Param>
IF @id IS NULL
BEGIN
INSERT INTO [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s] ([<Key_Param, sysobject, Key_Param>])
OUTPUT INSERTED.[id] INTO @inserted_ids
VALUES (@<Key_Param, sysobject, Key_Param>)
SELECT TOP 1 @id = [id] FROM @inserted_ids;
END
ELSE
BEGIN
UPDATE [<Schema, sysobject, dbo>].[<Table_Name, sysobject, Table_Name>s]
SET
[<Key_Param, sysobject, Key_Param>] = @<Key_Param, sysobject, Key_Param>
WHERE [id] = @id
END
END
GO
虽然可能需要使用linq,但是只需查询现有ID列表(或您的关键列)即可:
var dc = new MyDataContext();
var existingFoos = dc.Foos.ToList();
var newFoos = new List<Foo>();
foreach(var bar in whateverYoureIterating) {
// logic to add to newFoos
}
var foosToInsert = newFoos.Where(newFoo => !existingFoos.Any(existingFoo => newFoo.Id == existingFoo.Id));
dc.Foos.InsertAllOnSubmit(foosToInsert);
dc.SubmitChanges();
// use the next line if you plan on re-using existingFoos. If that's the case I'd wrap dc.SubmitChanges() in a try-catch as well.
existingFoos.AddRange(foosToInsert);
很遗憾,无法避免这个问题,因为Linq to SQL在执行插入之前不会检查数据库。唯一的方法是先查询数据库以确定是否存在重复记录,如果不存在,则添加该记录。
理想情况下,Linq to SQL应支持SQL列上的忽略重复键属性。但不幸的是目前它还不支持。