我尝试像这样批量合并到数据库表中:
public async Task UpdateCitiesAsync()
{
var request = new
{
apiKey = _apiKey,
modelName = "AddressGeneral",
calledMethod = "getCities"
};
string result = await ApiRequest(request);
var cityResponse = JsonConvert.DeserializeObject<NovaPoshtaResponse<City>>(result);
await _context.BulkInsertOrUpdateAsync(cityResponse.Data);
await _context.SaveChangesAsync();
}
但收到此异常:
MySqlConnector.MySqlException: "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '0 T.[Ref], T.[Description] INTO [CitiesTempdada41e4] FROM [Cities] AS T LEFT ...' at line 1"
在我决定将 AddRange 更改为批量扩展方法之前,上面的代码就可以工作。 BulkExtensions 版本是 6.0.2。
EF Core 中没有
BulkInsertOrUpdateAsync
。不存在 SQL Server 中的快速、最少日志记录 BULK INSERT
或 MySQL 和 MariaDB 中的 COPY
意义上的“批量更新”。该第三方扩展并未实现其声称的功能。
由于您已经在使用 MySqlConnector,因此您可以使用 MySqlBulkCopy 类从客户端执行
COPY
:
var dataTable = GetDataTableFromExternalSource();
// open the connection
using var connection = new MySqlConnection("...;AllowLoadLocalInfile=True");
await connection.OpenAsync();
// bulk copy the data
var bulkCopy = new MySqlBulkCopy(connection);
bulkCopy.DestinationTableName = "some_table_name";
var result = await bulkCopy.WriteToServerAsync(dataTable);
您可以通过设置 ConflictOption 属性来控制发生冲突时发生的情况,例如:
var bulkCopy = new MySqlBulkCopy(connection);
bulkCopy.DestinationTableName = "some_table_name";
bulkCopy.ConflictOption=MySqlBulkLoaderConflictOption.Replace;
var result = await bulkCopy.WriteToServerAsync(dataTable);
扩展实际上的作用是经典的 ETL 技术。它使用 SqlBulkCopy 将数据存储到它默默创建的临时表中,然后首先使用 INNER JOIN 更新目标
UPDATE TARGET
SET
...
FROM tempTable INNER JOIN Target on tempTable.ID=Target.ID
随后使用 LEFT JOIN 进行 INSERT 仅选取新行
INSERT INTO Target (...)
SELECT ....
FROM tempTable LEFT Join Target on tempTable.ID=Target.ID
Where Target.ID is NULL
虽然这看起来很方便,但它无法让您控制临时表的位置或索引、连接键、过滤条件或脚本为您提供的转换。