提问人:Zenith 提问时间:11/1/2023 更新时间:11/2/2023 访问量:95
在一个事务中批量执行 INSERT、UPDATE 和 DELETE [已关闭]
Bulk INSERT, UPDATE and DELETE in one transaction [closed]
问:
我正在尝试在 C# .NET 中对数据库进行批量“同步”(插入、更新和删除)。我正在使用 Dapper,因为由于其他原因,实体框架不适合该项目。有几个要求使我的问题更加困难:
- 同样,解决方案不能使用实体框架。
- 整个“同步”必须是一笔交易。
- sql 必须动态生成,因为需要同步的 DTO 是数据库中表的一对一副本。IE:表与具有某些属性的 .NET DTO 匹配,这些属性也作为列存在于数据库中。
Course
Course
- 该解决方案必须(显然)能够防止 SQL 注入攻击。
解决方案现在的工作原理:
- 另一个类调用一种方法来“同步”单个客户的所有 DTO。
repository.sync()
- 该客户在数据库中有自己的架构。架构的名称在同步调用时提供给存储库。
- 同步调用具有 param entitiesToSync 类型,其中
Dictionary<Type, Dictionary<Synchronizable, TransactionType>>
- 可同步是要同步的 DTO
- TransactionType 是具有值的枚举
{Added, Updated, Deleted}
- Type 是要同步的 DTO 的类型,它也等同于该 DTO 的表的名称。
- 调用 sync 方法后,entitiesToSync 将根据 TransactionType(添加、更新、删除)拆分为三个新字典。
我正在挣扎的:
- 对于添加的实体,应生成 INSERT sql 语句。
- 对于每个更新的实体,应生成单独的 UPDATE sql 语句。
- 对于已删除的实体,应生成 DELETE sql 语句。
- 所有这些语句都必须以安全的方式在一个事务中执行,以防止 SQL 注入。
我觉得这很困难的原因是,为了安全地生成 SQL 语句,需要使用参数。使用反射,我可以看到 DTO 具有的属性并生成语句。问题在于,实体的数量可能非常大,并且对每个项目使用唯一的参数可能会导致巨大的 DynamicParameter 对象。我相信SQL Server支持的参数数量是有限制的。解决方案是分批执行语句,但这是不可能的,因为同步应该是一个事务。
此外,为了防止解决方案使用大量资源,我希望生成尽可能少的语句和参数。我想我可以使用临时表来做到这一点,但我不确定如何做,因为我还需要动态生成这些临时表并在其中插入内容,这可能与直接插入实际表完全相同。
顶级域名;如何执行一个事务来批量插入、更新和删除数千条记录,以及如何从 .NET 类型的 PropertyInfo 生成执行此操作的代码?
答:
我处理通用实体同步的方式是这样的:
为您的表创建一个镜像暂存表,即 Course => CourseStaging。 该表可以具有与 target 相同的列,但可以为 NULL,以及一个标志列,该列指示如何处理实体 INSERT、UPDATE、DELETE
同步实体时,请确定它们属于哪个临时表,并使用填充临时表的 SQLBulkCopy。您仍然需要能够将属性映射到字段和数据类型,但我猜此代码已经可供您使用。您还可以使用 Dapper Ii guess 来填充暂存表。这要简单得多,因为这里没有 UPDATE / DELETE,只有简单的 INSERT
最后,调用一些 Procedure,该过程会生成一个 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
合并可以在显式事务中运行,最终您会得到一个完全更新的目标表。
评论
BULK INSERT
BULK UPDATE
BULK DELETE
DELETE MyTable WHERE Category=@category