当数据不包含主键时使用 EFCore.BulkExtensions 执行 UPSERT 的有效方法

Efficient way to perform an UPSERT with EFCore.BulkExtensions when data does not include primary key

我需要通过 API 将批量数据上传到数据库中,我正在考虑使用 EFCore.BulkExtensions。不幸的是,数据将不包括自动生成的主键 (Id)。

但是,我们有一个唯一的复合键,它将包含在数据中。我确实需要将 Id 保留为模型中的关键属性,因为我需要将其用作多个子项的外键(我已经能够使用 IncludeGraph 批量插入父项和子项,尽管我一直无法为 BulkUpdate 或 BulkInsertOrUpdate 进行设置 - 见下文)。

当我没有主键时,处理更新的最有效方法是什么?我是否应该使用 BulkRead 获取基于唯一复合键的 Id,选择所有 3 个字段,然后将其映射到记录列表中?或者是否有另一种方法来处理这个问题(可能类似于 ColumnPrimaryKeyExpression for Entity Framework Extensions)。

如果父记录是Update,子记录也是Upsert,会不会有问题?这些记录会遇到与父项相同的缺少主键和唯一复合键的问题。

提前致谢!

我建议考虑替代方案。例如 linq2db.EntityFrameworkCore 拥有与批量操作相关的一切。请注意,我是创作者之一。

如何插入或更新百万行:

var items = ...

using var db = context.CreateLinqToDBConnection();

// temporary table will be crated and items will be inserted as fast as possible
using var temp = db.CreateTempTable(items);

var destinationTable = context.SomeTable.ToLinqToDBTable();
// or
var destinationTable = db.GetTable<SomeTable>();

destinationTable
    .Merge()
    .Using(temp)
    .On((target, source) => target.SomeValue == source.SomeValue)
    .InsertWhenNotMatched(source => new SomeTable
    {
        SomeValue = source.SomeValue
        ... // other fields
    })
    .UpdateWhenMatched((target, source) => new SomeTable
    {
        OtherValue = source.OtherValue 
        ... // other fields
    })
    .Merge();

我决定使用 .AsNoTracking() 基于密钥通过 Linq 查询提取我需要的数据,然后将 ID 与要更新的数据进行匹配。由于其他一些限制,我需要在每条记录上使用 ForEach 到 运行 一些业务规则,然后 运行 通过 BulkUpdate 无论如何,希望匹配同时完成。