Entity Framework 和 Firebird DB 方言 1 - 不生成兼容 sql
Entity Framework and Firebird DB Dialect 1 - not generating compatible sql
我正在尝试在 firebird 数据库上使用 EF 设置一个项目,但它生成了 Firebird 数据库拒绝的额外引号。
数据库已经存在,并且那里有一条与此查询匹配的记录。
错误是
FbException:动态 SQL 错误
SQL 错误代码 = -104
令牌未知 - 第 2 行,第 4 列
.
但是,如果我删除它在 sql 中生成的引号,查询就会运行。
示例
using (var context = new ContextManager())
{
var accounts = context.Accounts.Where(x => x.OBJID == 1).ToList();
}
生成sql
SELECT
"A"."OBJID" AS "OBJID"
FROM "ACCOUNT" AS "A"
配置文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<entityFramework>
<defaultConnectionFactory type="FirebirdSql.Data.EntityFramework6.FbConnectionFactory, EntityFramework.Firebird" />
<providers>
<provider invariantName="FirebirdSql.Data.FirebirdClient" type="FirebirdSql.Data.EntityFramework6.FbProviderServices, EntityFramework.Firebird" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.data>
<DbProviderFactories>
<remove invariant="FirebirdSql.Data.FirebirdClient" />
<add name="FirebirdClient Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".NET Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient" />
</DbProviderFactories>
</system.data></configuration>
上下文class
public class ContextManager : DbContext
{
public ContextManager() : base(new FbConnection("database=xxxx.fdb;DataSource=localhost;user=xxx;password=xxxxx"),true)
{
}
public ContextManager(string connString) : base(new FbConnection(connString), true)
{
//this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
public DbSet<Account> Accounts { get; set; }
}
账户模型
[Table("ACCOUNT")]
public class Account
{
[Key]
public int OBJID { get; set; }
}
更新 - 检查并看到方言 1 已设置,所以我更新了查询字符串以表示它,查询没有更改但错误确实发生了
FbException:动态 SQL 错误
SQL 错误代码 = -104
令牌未知 - 第 2 行,第 4 列
.
问题是您的数据库是方言 1,并且 Entity Framework 引用了对象名称。不幸的是,方言 1 不支持引用的对象名称,而是将其解释为字符串。这会导致令牌未知错误,因为解析器不需要字符串,而是对象名称。
我已经有一段时间没用 entity framework 做任何事情了(我通常在 Java 中编程),我不确定是否有禁用引用的选项。
根据 Firebird 错误跟踪器中的这张票,Firebird Entity Framework 支持不支持也不会支持方言 1:DNET-580.
因此,除非您将数据库升级到方言 3,否则您将无法使用 Entity Framework。请注意,从方言 1 升级到方言 3 可能并不简单,尤其是如果您的应用程序依赖于方言 1 的特定语法(例如,字符串的双引号)或行为(整数的浮点除法)。
解决方法
一个潜在的解决方法是将您的连接方言明确指定为方言 3(Firebird ADO.net 提供程序的连接 属性 Dialect=3
)。这将允许您使用方言 3 语法查询数据库。请注意,行为可能存在一些差异,因为方言 3 有许多不同的规则。
虽然我有点惊讶,因为我测试了一些最新版本的 Firebird ADO.net 提供程序,它默认为方言 3,除非明确设置为 1,所以这应该不是问题完全没有。
方言 3 的类似问题
答案的这一部分假定一个方言 3 数据库,其中 table 实际上称为 ACCOUNTS
,而不是 Accounts
。这不会导致令牌未知,但会导致 table 未知错误。
在这种情况下,问题是默认配置从对象派生名称,并且会引用名称。方言 3 中带引号的名称区分大小写(不带引号的名称不区分大小写,但存储(和比较)为大写)。
您可以做的是通过注释您的对象来覆盖 table 名称:
[Table("ACCOUNTS")]
public class Account
{
[Key]
public int OBJID { get; set; }
}
您可以使用的另一个选项是流利 API,但我自己从未使用过它,所以我不完全确定您需要在哪里指定它(我认为在您的 DbContext
).
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Changing Database table name to Metadata
modelBuilder.Entity<Account>()
.ToTable("ACCOUNTS");
}
可能还有其他选项会影响命名约定。
另见 Entity Framework Code First - Changing a Table Name
我正在尝试在 firebird 数据库上使用 EF 设置一个项目,但它生成了 Firebird 数据库拒绝的额外引号。
数据库已经存在,并且那里有一条与此查询匹配的记录。 错误是 FbException:动态 SQL 错误 SQL 错误代码 = -104 令牌未知 - 第 2 行,第 4 列 .
但是,如果我删除它在 sql 中生成的引号,查询就会运行。
示例
using (var context = new ContextManager())
{
var accounts = context.Accounts.Where(x => x.OBJID == 1).ToList();
}
生成sql
SELECT
"A"."OBJID" AS "OBJID"
FROM "ACCOUNT" AS "A"
配置文件
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<entityFramework>
<defaultConnectionFactory type="FirebirdSql.Data.EntityFramework6.FbConnectionFactory, EntityFramework.Firebird" />
<providers>
<provider invariantName="FirebirdSql.Data.FirebirdClient" type="FirebirdSql.Data.EntityFramework6.FbProviderServices, EntityFramework.Firebird" />
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="FirebirdSql.Data.FirebirdClient" publicKeyToken="3750abcc3150b00c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.data>
<DbProviderFactories>
<remove invariant="FirebirdSql.Data.FirebirdClient" />
<add name="FirebirdClient Data Provider" invariant="FirebirdSql.Data.FirebirdClient" description=".NET Framework Data Provider for Firebird" type="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory, FirebirdSql.Data.FirebirdClient" />
</DbProviderFactories>
</system.data></configuration>
上下文class
public class ContextManager : DbContext
{
public ContextManager() : base(new FbConnection("database=xxxx.fdb;DataSource=localhost;user=xxx;password=xxxxx"),true)
{
}
public ContextManager(string connString) : base(new FbConnection(connString), true)
{
//this.Configuration.LazyLoadingEnabled = false;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
public DbSet<Account> Accounts { get; set; }
}
账户模型
[Table("ACCOUNT")]
public class Account
{
[Key]
public int OBJID { get; set; }
}
更新 - 检查并看到方言 1 已设置,所以我更新了查询字符串以表示它,查询没有更改但错误确实发生了 FbException:动态 SQL 错误 SQL 错误代码 = -104 令牌未知 - 第 2 行,第 4 列 .
问题是您的数据库是方言 1,并且 Entity Framework 引用了对象名称。不幸的是,方言 1 不支持引用的对象名称,而是将其解释为字符串。这会导致令牌未知错误,因为解析器不需要字符串,而是对象名称。
我已经有一段时间没用 entity framework 做任何事情了(我通常在 Java 中编程),我不确定是否有禁用引用的选项。
根据 Firebird 错误跟踪器中的这张票,Firebird Entity Framework 支持不支持也不会支持方言 1:DNET-580.
因此,除非您将数据库升级到方言 3,否则您将无法使用 Entity Framework。请注意,从方言 1 升级到方言 3 可能并不简单,尤其是如果您的应用程序依赖于方言 1 的特定语法(例如,字符串的双引号)或行为(整数的浮点除法)。
解决方法
一个潜在的解决方法是将您的连接方言明确指定为方言 3(Firebird ADO.net 提供程序的连接 属性 Dialect=3
)。这将允许您使用方言 3 语法查询数据库。请注意,行为可能存在一些差异,因为方言 3 有许多不同的规则。
虽然我有点惊讶,因为我测试了一些最新版本的 Firebird ADO.net 提供程序,它默认为方言 3,除非明确设置为 1,所以这应该不是问题完全没有。
方言 3 的类似问题
答案的这一部分假定一个方言 3 数据库,其中 table 实际上称为 ACCOUNTS
,而不是 Accounts
。这不会导致令牌未知,但会导致 table 未知错误。
在这种情况下,问题是默认配置从对象派生名称,并且会引用名称。方言 3 中带引号的名称区分大小写(不带引号的名称不区分大小写,但存储(和比较)为大写)。
您可以做的是通过注释您的对象来覆盖 table 名称:
[Table("ACCOUNTS")]
public class Account
{
[Key]
public int OBJID { get; set; }
}
您可以使用的另一个选项是流利 API,但我自己从未使用过它,所以我不完全确定您需要在哪里指定它(我认为在您的 DbContext
).
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Changing Database table name to Metadata
modelBuilder.Entity<Account>()
.ToTable("ACCOUNTS");
}
可能还有其他选项会影响命名约定。
另见 Entity Framework Code First - Changing a Table Name