我必须在SQL Server数据库中定期插入一些数据。但是我读取数据的源会重复之前插入的一些数据。当我使用Linq-to-SQL插入数据库时,某些数据会被复制,或者引发主键冲突异常,具体取决于主键。
如何在没有重复的情况下插入数据,没有例外?我不想用try-catch来避免异常,因为一旦引发异常,就不会插入其余的数据。
更新我还找到了自己的解决方案:我写了一个重复的条目删除存储过程,它在InsertAllOnSubmit + SubmitChanges之后运行
答案 0 :(得分:6)
您所要做的就是创建类的新实例,然后在表上调用InsertOnSumbit():
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);
答案 1 :(得分:2)
不幸的是,由于Linq to SQL在执行插入之前没有检查数据库,因此无法绕过它。执行此操作的唯一方法是首先查询数据库 以确定是否存在重复记录,然后添加记录(如果不存在)。
理想情况下,Linq to SQL将支持SQL列上的Ignore Duplicate Keys属性。但不幸的是,目前还没有。