【问题标题】:How to insert only new records using Linq-to-SQL?如何使用 Linq-to-SQL 仅插入新记录?
【发布时间】:2009-04-07 13:32:07
【问题描述】:

我必须定期在我的 SQL Server 数据库中插入一些数据。但是我读取数据的提要重复了之前插入的一些数据。当我使用 Linq-to-SQL 将某些数据插入数据库时​​,要么重复某些数据,要么引发主键冲突异常,具体取决于主键。

如何无重复无异常地插入数据?我不想通过 try-catch 来避免异常,因为一旦引发异常,其余数据就不会被插入。

更新我也找到了自己的解决方案:我写了一个重复条目删除存储过程,在 InsertAllOnSubmit + SubmitChanges 之后运行

【问题讨论】:

    标签: .net linq linq-to-sql insert


    【解决方案1】:

    你所要做的就是创建你的类的一个新实例,然后在表上调用 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);
    

    【讨论】:

    • LINQ 解决方案似乎很慢。查询一个巨大的表来加载内存中的内容对我来说似乎是不可行的。也许我应该坚持使用 SP 方法。
    • 这就是我的想法...不过,您可以通过仅选择您真正需要的属性来加快 LINQ 解决方案的速度...例如,只选择 ID 列。此外,如果您可以重复使用“现有”查询进行多次运行,那也会有所帮助。
    【解决方案2】:

    不幸的是,没有办法绕过它,因为 Linq to SQL 在执行插入之前不会检查数据库。这样做的唯一方法是首先查询数据库以确定是否存在重复记录,如果不存在则添加记录。

    理想情况下,Linq to SQL 将支持 SQL 列上的 Ignore Duplicate Keys 属性。但不幸的是,目前还没有。

    【讨论】:

    • 2018 年呢?你现在知道方法了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-04
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 2012-03-01
    • 1970-01-01
    相关资源
    最近更新 更多