.net 如何使用Linq to SQL仅插入新记录?

.net 如何使用Linq to SQL仅插入新记录?,.net,linq,linq-to-sql,insert,.net,Linq,Linq To Sql,Insert,我必须定期在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列上使用标识(1,1)设置。这在LINQ实体的id列上声明,如下所示:

[Column(AutoSync = AutoSync.OnInsert, IsPrimaryKey = true, IsDbGenerated = true)]
public Int32 Id { get; set; }
为了避免重复,您真正需要的是我们在my shop中所称的“附加”功能。IMHO,这最容易通过存储过程实现-我们甚至有一个用于它的模板:

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
使用[]
去
创建过程[].[附加]
(
@id INT输出,
@ 
)
作为
开始
从[].[s](NOLOCK)中选择@id=[id],其中[]=@
如果@id为空
开始
插入到[].[s]([])中
输出已插入。[id]到@INSERTED_id
值(@)
从@inserted_id中选择TOP 1@id=[id];
结束
其他的
开始
更新[][s]
设置
[] = @
其中[id]=@id
结束
结束
去
不过,可以在linq中执行此操作,只需查询现有ID的列表(或键入的任何列):

var dc=new MyDataContext();
var existingFoos=dc.Foos.ToList();
var newFoos=新列表();
foreach(无论您的操作是什么,都有var bar){
//添加到newFoos的逻辑
}
var foosToInsert=newFoos.Where(newFoo=>!existingFoos.Any(existingFoo=>newFoo.Id==existingFoo.Id));
dc.Foos.InsertAllOnSubmit(foosToInsert);
dc.提交更改();
//如果计划重新使用现有的Foos,请使用下一行。如果是这样的话,我也会将dc.SubmitChanges()包装在一个try-catch中。
现有foos.AddRange(foosToInsert);

不幸的是,这是无法避免的,因为Linq to SQL在执行插入之前不会检查数据库。唯一的方法是首先查询数据库以确定重复记录是否存在,如果不存在,则添加该记录


理想情况下,LINQtoSQL将支持SQL列上的属性。但不幸的是,目前还没有。LINQ解决方案似乎相当缓慢。查询一个巨大的表并在内存中加载内容对我来说似乎是不可行的。也许我应该坚持SP方法。这就是我想的。。。不过,只需选择真正需要的属性,就可以加快LINQ解决方案的速度。。。例如,只有ID列。此外,如果您可以对多次运行重复使用“现有”查询,这也会有所帮助。2018年呢?你现在知道路了吗?
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);