在一笔事务中批量插入、更新和删除

问题描述 投票:0回答:1

我正在尝试对 C# .NET 中的数据库进行批量“同步”(插入、更新和删除)。我使用 Dapper 是因为 Entity Framework 由于其他原因不适合该项目。有几个要求使我的问题变得格外困难:

  • 同样,该解决方案不能使用实体框架。
  • 整个“同步”必须是一笔交易。
  • sql 必须动态生成,因为需要同步的 DTO 是数据库中表的一对一副本。 IE:表
    Course
    与 .NET DTO
    Course
    匹配,其某些属性也作为列存在于数据库中。
  • 该解决方案必须(显然)能够抵御 SQL 注入攻击。

该解决方案目前如何运作:

  • 不同的类调用
    repository.sync()
    方法来“同步”单个客户的所有 DTO。
  • 该客户在数据库中有自己的模式。架构的名称在同步调用时提供给存储库。
  • 同步调用有一个类型为
    Dictionary<Type, Dictionary<Synchronizable, TransactionType>>
    的参数EntityToSync,其中
    • Synchronized是要同步的DTO
    • TransactionType 是一个带有值的枚举
      {Added, Updated, Deleted}
    • Type 是要同步的 DTO 的类型,也相当于该 DTO 的表名称。
  • 调用sync方法后,entitiesToSync根据TransactionType(添加、更新、删除)分为三个新字典。

我正在努力解决的问题:

  • 对于添加的实体,应生成 INSERT sql 语句。
  • 对于每个更新的实体,应生成单独的 UPDATE sql 语句。
  • 对于删除的实体,应生成 DELETE sql 语句。
  • 所有这些语句必须以安全的方式在一个事务中执行,以防止 SQL 注入。

我觉得这很困难的原因是为了安全地生成SQL语句,需要使用参数。使用反射,我可以查看 DTO 具有的属性并生成语句。问题是实体的数量可能非常大,并且为每个项目使用唯一的参数可能会导致巨大的 DynamicParameter 对象。我相信 SQL Server 支持的参数数量是有限的。解决方案是分部分执行语句,但这是不可能的,因为同步应该是一个事务。

此外,为了防止解决方案使用大量资源,我希望生成尽可能少的语句和参数。我想我可以使用临时表来执行此操作,但我不确定如何操作,因为我还需要动态生成这些临时表并向其中插入内容,这可能与直接插入实际表完全相同。

TLDR;如何执行一个事务来批量插入、更新和删除数千条记录,以及如何从 .NET 类型的 PropertyInfo 生成执行此操作的代码?

c# sql .net sql-server dapper
1个回答
0
投票

我处理通用实体同步的方式是这样的:

  1. 为您的表创建一个镜像暂存表,即。课程 => 课程分期。 该表可以具有与目标相同的列,但可以为 NULL,以及一个标志列,该标志列说明如何处理实体、INSERT、UPDATE、DELETE

  2. 同步实体时,请找出它们属于哪个临时表,并使用 SQLBulkCopy 填充临时表。您仍然需要能够将属性映射到字段以及数据类型,但我猜您已经可以使用此代码。我猜您还可以使用 Dapper 来填充暂存表。这要简单得多,因为这里没有更新/删除,只有简单的插入

  3. 最后,您调用一些过程来构建一个 MERGE 语句,如下所示:

MERGE {TARGET} t
USING {SOURCE_STAGE} s
 ON s.{ID} = t.{ID}
WHEN MATCHED AND s.flag = 'insert' THEN INSERT (
 {COLUMNS}) VALUES({s.columns})
WHEN MATCHED AND s.flag = 'update' THEN UPDATE
SET {COLUMN_1} = s.{COLUMN_1}
...
WHEN MATCHED AND s.flag = 'delete' THEN DELETE

您需要动态生成内容,但这应该不会太难,您始终可以在 sys.columns 中查找列。

合并可以在显式事务中运行,最终你有一个完全更新的目标表

© www.soinside.com 2019 - 2024. All rights reserved.