【问题标题】:How add multiple rows with one Insert query in EF如何在 EF 中使用一个插入查询添加多行
【发布时间】:2025-12-15 06:45:01
【问题描述】:

我有一个长度未知的字符串列表。 我正在将它们添加到数据库中:

if (somenteNovasClas.Any()) {
    foreach (string item in wsClassificacoes) {
        dc.Classificacaos.Add(new Classificacao { Descricao = item });
    }
    dc.SaveChanges();
}

但 EF 会为每一行生成一个INSERT

exec sp_executesql N'insert [dbo].[Classificacao]([Descricao], [Excluido])
values (@0, @1)
select [CodClassificacao]
from [dbo].[Classificacao]
where @@ROWCOUNT > 0 and [CodClassificacao] = scope_identity()',N'@0 varchar(255),@1 bit',@0='Mercado',@1=0
go
exec sp_executesql N'insert [dbo].[Classificacao]([Descricao], [Excluido])
values (@0, @1)
select [CodClassificacao]
from [dbo].[Classificacao]
where @@ROWCOUNT > 0 and [CodClassificacao] = scope_identity()',N'@0 varchar(255),@1 bit',@0='Concorrência',@1=0
go

我想知道如何一次性插入 EF 将生成如下命令:

INSERT INTO Table (column)
VALUES ([array[0]]), ([array[1]]), ...

而不是一个插入foreach.. 有什么想法吗?

【问题讨论】:

  • 你怎么知道 EF 为每一行生成一个插入?
  • 很公平。请显示您的 C# 代码。我怀疑您没有按照 MSFT 的意图编写它。我很确定 EF 可以进行批量插入。
  • 我不确定您要达到的目标。除非您从 SqlBulkCopy 或外部数据源批量插入,否则这是 AFAIK 完成的唯一方法,而且您这样做的方式仍然非常快。
  • EF 永远不会使用所谓的行构造函数生成 sql 语句。这不是它的功能之一。

标签: c# .net linq entity-framework


【解决方案1】:

Entity Framework 核心 (3+) 在这方面得到了显着改进。当有多个具有相同形状的插入时,对于Sql Server,它将生成MERGE 语句,而不是单独的INSERT 语句。

例如,添加 10 个新产品:

DECLARE @inserted0 TABLE ([Id] int, [_Position] [int]);
MERGE [Products] USING (
VALUES (@p0, @p1, @p2, @p3, @p4, 0),
(@p5, @p6, @p7, @p8, @p9, 1),
(@p10, @p11, @p12, @p13, @p14, 2),
(@p15, @p16, @p17, @p18, @p19, 3),
(@p20, @p21, @p22, @p23, @p24, 4),
(@p25, @p26, @p27, @p28, @p29, 5),
(@p30, @p31, @p32, @p33, @p34, 6),
(@p35, @p36, @p37, @p38, @p39, 7),
(@p40, @p41, @p42, @p43, @p44, 8),
(@p45, @p46, @p47, @p48, @p49, 9)) AS i ([Image], [ProductName], [QuantityPerUnit], [StartDate], [UnitPrice], _Position) ON 1=0
WHEN NOT MATCHED THEN
INSERT ([Image], [ProductName], [QuantityPerUnit], [StartDate], [UnitPrice])
VALUES (i.[Image], i.[ProductName], i.[QuantityPerUnit], i.[StartDate], i.[UnitPrice])
OUTPUT INSERTED.[Id], i._Position
INTO @inserted0;

SELECT [t].[Id], [t].[RowVersion] FROM [Products] t
INNER JOIN @inserted0 i ON ([t].[Id] = [i].[Id])
ORDER BY [i].[_Position];

最后的SELECT 查询用于将生成的IdRowVersion 值反馈到C# 对象中。

当有大量插入时,EF不会达到最大参数阈值,它只是生成多个MERGE语句块。

它与带有值构造函数的插入语句不一样,但仍然比无数单独的插入要好得多。

【讨论】:

    【解决方案2】:

    查看这篇文章:Fastest Way of Inserting in Entity Framework

    实体框架并不是真的要开箱即用,但看起来人们已经创建了一些扩展:https://efbulkinsert.codeplex.com/

    【讨论】: