.Net Core 3 Entity Framework 带有 Firebird 数据库和字符集 none

.Net Core 3 Entity Framework with Firebird database and charset none

我有一个遗留的 Firebird (2.5.9) 数据库,它创建时没有使用字符集,并且由于它正在生产中,所以所有数据都是使用 WIN1252 插入的。我正在迁移到 .Net Core 并使用 FirebirdSql.Data.FirebirdClient 作为提供程序(在 .Net Framework 和 .Net Core 中)。

在 .Net Framework 和 EF 6 中,我只需在连接字符串中设置字符集 WIN1252。

在 .Net Core 3.1 中,连接字符串的字符集仅在阅读时使用,因为我必须首先在代码中设置列类型,如下所示:

entity.Property(e => e.description).HasMaxLength(255).HasColumnType("VARCHAR(255) CHARACTER SET WIN1252");

使其以相同的编码保存字符串。

我现在面临的问题与以下事实有关:所有查询参数似乎都使用 UTF8,这是 .Net Core 中新的默认编码,当然,一些特殊字符是不同的。

因此,例如,假设我有一条记录,在字段 description 中包含重音字符,例如“èèè”。

以下查询未能检索到它:

string filter = "èèè";
Product p = context.Products.Where(x => x.description == filter).FirstOrDefault();

此查询被翻译成:

SELECT "a"."product_id", ... , "a"."description"
FROM "products" AS "a"
WHERE "a"."description" = CAST(@__filter_0 AS VARCHAR(8191))

这种转换也在 .Net Framework 中发生,但像这样的查询在那里可以正常工作。

此外,如果有多个参数,我会得到错误

Implementation limit exceeded. block size exceeds implementation restriction

这正是此 question 中描述的内容,即使那是在 EF5 和 .Net Framework 中。基本上,您似乎很容易达到 64k 的行大小限制,因为 VARCHAR(8191) 在字节方面将权重更多地转换为 UTF8。

我确定一种解决方案是升级到具有 UTF8 编码的新数据库并正确编码所有数据,但目前我希望尽可能避免这种情况。我也不认为这会解决块大小错误。

有没有办法让它像在 .Net Framework 中一样工作?

我刚在 firebird-net-provider Google Group

收到 Jiří Činčura 的答复

.Net Framework 和 .Net Core 之间行为不同的原因实际上是由于 .Net Core (UTF8) 的默认编码。

我的数据库将 字符集设置为 none。所以会发生什么,即使你像这样设置列类型:

.HasColumnType("VARCHAR(255) CHARACTER SET WIN1252");

提供商在比较值时始终使用数据库中的列字符集。 这意味着,如果您首先在代码中设置列类型,您只会修复字符串保存,但当提供者需要比较值时,他会检查数据库中的列配置。

所以解决方案是在 columns/database 和 check/copy 数据上正确 define/fix 字符集。

就个人而言,我没有在所有列上强制使用 WIN1252 字符集,而是继续将整个数据库转换为 UTF8,这样,即使我将列字符集保留为 none,字符串也已保存在相同的 .Net Core 默认编码,它也更适合未来。

行大小限制问题在某种程度上是无关的,它只是在您开始使用 UTF8 时会发生的事情。幸运的是,您可以在上下文配置中设置此选项

new FbDbContextOptionsBuilder(optionsBuilder).WithExplicitParameterTypes(false);

减少这些 varchar 转换。

附加信息

我使用 fbclone 转换数据库,因为它可以克隆一个数据库,使用相同的结构将数据从一个数据库泵送到另一个数据库,同时处理不同的字符集。

此外,您可能需要检查索引,因为在 Firebird 2.x 中,最大大小是页面大小的四分之一 (source),并且 UTF8 中的字符串在内部存储为 4 bytes/char 因此,如果您像我一样来自 WIN1252 (1 byte/char),您可以轻松达到该限制。