.NET - 在 Visual FoxPro 中使用 Entity Framework - 错误 "Compiled code for this line is too long."

.NET - using Entity Framework with Visual FoxPro - error "Compiled code for this line is too long."

我正在尝试将 Entity Framework 6 (EF) 与 Visual FoxPro 数据库一起使用(使用来自 NuGet 的包 VFPEntityFrameworkProvider2),我能够很好地建立连接。我能够从大多数表中加载数据。

当我尝试检索具有大约 240 个字段的特定类型的 DbSet 时出现问题。抛出的异常包含消息:

Compiled code for this line is too long.

据我所知,EF 编写了 SQL select 语句来检索数据,并且此语句太长。当我使用调试器检查局部变量时,我看到一个 SQL 语句,其长度接近 16000 个字符,而 maximum allowed command length for VFP is 8,192 bytes

我不太确定如何解决这个问题,因为我对 EF 还很陌生。我想我可以编辑一些生成的代码,或者编写一些自定义处理程序。也许我可以批量检索字段,然后组合对象。

此外,我相信可以将我的实体分解为类型和子类型;也许如果我这样做,一次只会检索一部分字段。

谁能建议我用什么方式解决这个限制?

添加的注释:

不能选择使用不同的数据库。我坚持使用 FoxPro 和这个特定的架构。但是,我可以自由地改变解决问题的方法。当然,我可以自己写DB访问代码,但是如果能用EF就更好了。

发送到 VFP 的查询实际上看起来像这样:

SELECT 
E1.Wn_Ref, 
E1.Wn_Surname, 
E1.Wn_Forenam, 
E1.Wn_Dirctr, 
...
E1.Wn_Chqno, 
 CAST( E1.Wn_Lelval AS n(20,2)) AS Wn_Lelval, 
E1.Wn_Dirstpd, 
...
E1.Wn_Leavdt, 
 CAST( E1.Wn_Grsprv AS n(20,2)) AS Wn_Grsprv, 
 CAST( E1.Wn_Taxprv AS n(20,2)) AS Wn_Taxprv, 
E1.Wn_Ovride, 
E1.Wn_Nichgpr, 
...
E1.Wn_Totabs, 
 CAST( E1.Wn_Tgrspay AS n(20,2)) AS Wn_Tgrspay, 
 CAST( E1.Wn_Tottax AS n(20,2)) AS Wn_Tottax, 
 CAST( E1.Wn_Totpens AS n(20,2)) AS Wn_Totpens, 
 CAST( E1.Wn_Totsspr AS n(20,2)) AS Wn_Totsspr, 
 CAST( E1.Wn_Totsmp AS n(20,2)) AS Wn_Totsmp, 
 CAST( E1.Wn_Totchrt AS n(20,2)) AS Wn_Totchrt, 
 CAST( E1.Wn_Totcmee AS n(20,2)) AS Wn_Totcmee, 
 CAST( E1.Wn_Totcmer AS n(20,2)) AS Wn_Totcmer, 
 CAST( E1.Wn_Tcmeeyr AS n(20,2)) AS Wn_Tcmeeyr, 
 CAST( E1.Wn_Tcmeryr AS n(20,2)) AS Wn_Tcmeryr, 
 CAST( E1.Wn_Totpenl AS n(20,2)) AS Wn_Totpenl, 
 CAST( E1.Wn_Totpay AS n(20,2)) AS Wn_Totpay, 
 CAST( E1.Wn_Tothol AS n(20,1)) AS Wn_Tothol, 
 CAST( E1.Wn_Roundbf AS n(20,2)) AS Wn_Roundbf, 
E1.Wl_Totsspd, 
E1.Wl_Totabs, 
 CAST( E1.Wl_Tgrspay AS n(20,2)) AS Wl_Tgrspay, 
 CAST( E1.Wl_Tottax AS n(20,2)) AS Wl_Tottax, 
 CAST( E1.Wl_Totpens AS n(20,2)) AS Wl_Totpens, 
 CAST( E1.Wl_Totsspr AS n(20,2)) AS Wl_Totsspr, 
 CAST( E1.Wl_Totsmp AS n(20,2)) AS Wl_Totsmp, 
 CAST( E1.Wl_Totchrt AS n(20,2)) AS Wl_Totchrt, 
 CAST( E1.Wl_Totcmee AS n(20,2)) AS Wl_Totcmee, 
 CAST( E1.Wl_Totcmer AS n(20,2)) AS Wl_Totcmer, 
 CAST( E1.Wl_Tcmeeyr AS n(20,2)) AS Wl_Tcmeeyr, 
 CAST( E1.Wl_Tcmeryr AS n(20,2)) AS Wl_Tcmeryr, 
 CAST( E1.Wl_Totpenl AS n(20,2)) AS Wl_Totpenl, 
 CAST( E1.Wl_Totpay AS n(20,2)) AS Wl_Totpay, 
 CAST( E1.Wl_Tothol AS n(20,1)) AS Wl_Tothol, 
 CAST( E1.Wl_Txb AS n(20,2)) AS Wl_Txb, 
 CAST( E1.Wl_Tax AS n(20,2)) AS Wl_Tax, 
 CAST( E1.Wl_Net AS n(20,2)) AS Wl_Net, 
 CAST( E1.Wl_Erni AS n(20,2)) AS Wl_Erni, 
 CAST( E1.Wl_Eeni AS n(20,2)) AS Wl_Eeni, 
 CAST( E1.Wl_Cnoni AS n(20,2)) AS Wl_Cnoni, 
 CAST( E1.Wl_Nien AS n(20,2)) AS Wl_Nien, 
 CAST( E1.Wl_Nieco AS n(20,2)) AS Wl_Nieco, 
 CAST( E1.Wl_Compee AS n(20,2)) AS Wl_Compee, 
 CAST( E1.Wl_Comper AS n(20,2)) AS Wl_Comper, 
 CAST( E1.Wl_Pen AS n(20,2)) AS Wl_Pen, 
 CAST( E1.Wl_Penbl AS n(20,2)) AS Wl_Penbl, 
 CAST( E1.Wl_Roundcf AS n(20,2)) AS Wl_Roundcf, 
 CAST( E1.Wn_Ssp1 AS n(20,2)) AS Wn_Ssp1, 
 CAST( E1.Wn_Ssp2 AS n(20,2)) AS Wn_Ssp2, 
 CAST( E1.Wn_Ssp3 AS n(20,2)) AS Wn_Ssp3, 
 CAST( E1.Wn_Ssp4 AS n(20,2)) AS Wn_Ssp4, 
 CAST( E1.Wn_Ssp5 AS n(20,2)) AS Wn_Ssp5, 
 CAST( E1.Wn_Ssp6 AS n(20,2)) AS Wn_Ssp6, 
 CAST( E1.Wn_Ssp7 AS n(20,2)) AS Wn_Ssp7, 
 CAST( E1.Wn_Ssp8 AS n(20,2)) AS Wn_Ssp8, 
E1.Wn_Ssprate, 
...
E1.Wn_Pwxretn
FROM (SELECT 
Wname.Wn_Ref, 
...
Wname.Wn_Chqno, 
 CAST( Wname.Wn_Lelval AS n(20,2)) AS Wn_Lelval, 
Wname.Wn_Dirstpd, 
Wname.Wn_Payfrq, 
Wname.Wn_Birth, 
Wname.Wn_Startdt, 
Wname.Wn_Leavdt, 
 CAST( Wname.Wn_Grsprv AS n(20,2)) AS Wn_Grsprv, 
 CAST( Wname.Wn_Taxprv AS n(20,2)) AS Wn_Taxprv, 
Wname.Wn_Ovride, 
...
Wname.Wn_Totabs, 
 CAST( Wname.Wn_Tgrspay AS n(20,2)) AS Wn_Tgrspay, 
 CAST( Wname.Wn_Tottax AS n(20,2)) AS Wn_Tottax, 
 CAST( Wname.Wn_Totpens AS n(20,2)) AS Wn_Totpens, 
 CAST( Wname.Wn_Totsspr AS n(20,2)) AS Wn_Totsspr, 
 CAST( Wname.Wn_Totsmp AS n(20,2)) AS Wn_Totsmp, 
 CAST( Wname.Wn_Totchrt AS n(20,2)) AS Wn_Totchrt, 
 CAST( Wname.Wn_Totcmee AS n(20,2)) AS Wn_Totcmee, 
 CAST( Wname.Wn_Totcmer AS n(20,2)) AS Wn_Totcmer, 
 CAST( Wname.Wn_Tcmeeyr AS n(20,2)) AS Wn_Tcmeeyr, 
 CAST( Wname.Wn_Tcmeryr AS n(20,2)) AS Wn_Tcmeryr, 
 CAST( Wname.Wn_Totpenl AS n(20,2)) AS Wn_Totpenl, 
 CAST( Wname.Wn_Totpay AS n(20,2)) AS Wn_Totpay, 
 CAST( Wname.Wn_Tothol AS n(20,1)) AS Wn_Tothol, 
 CAST( Wname.Wn_Roundbf AS n(20,2)) AS Wn_Roundbf, 
Wname.Wl_Totsspd, 
Wname.Wl_Totabs, 
 CAST( Wname.Wl_Tgrspay AS n(20,2)) AS Wl_Tgrspay, 
 CAST( Wname.Wl_Tottax AS n(20,2)) AS Wl_Tottax, 
 CAST( Wname.Wl_Totpens AS n(20,2)) AS Wl_Totpens, 
 CAST( Wname.Wl_Totsspr AS n(20,2)) AS Wl_Totsspr, 
 CAST( Wname.Wl_Totsmp AS n(20,2)) AS Wl_Totsmp, 
 CAST( Wname.Wl_Totchrt AS n(20,2)) AS Wl_Totchrt, 
 CAST( Wname.Wl_Totcmee AS n(20,2)) AS Wl_Totcmee, 
 CAST( Wname.Wl_Totcmer AS n(20,2)) AS Wl_Totcmer, 
 CAST( Wname.Wl_Tcmeeyr AS n(20,2)) AS Wl_Tcmeeyr, 
 CAST( Wname.Wl_Tcmeryr AS n(20,2)) AS Wl_Tcmeryr, 
 CAST( Wname.Wl_Totpenl AS n(20,2)) AS Wl_Totpenl, 
 CAST( Wname.Wl_Totpay AS n(20,2)) AS Wl_Totpay, 
 CAST( Wname.Wl_Tothol AS n(20,1)) AS Wl_Tothol, 
 CAST( Wname.Wl_Txb AS n(20,2)) AS Wl_Txb, 
 CAST( Wname.Wl_Tax AS n(20,2)) AS Wl_Tax, 
 CAST( Wname.Wl_Net AS n(20,2)) AS Wl_Net, 
 CAST( Wname.Wl_Erni AS n(20,2)) AS Wl_Erni, 
 CAST( Wname.Wl_Eeni AS n(20,2)) AS Wl_Eeni, 
 CAST( Wname.Wl_Cnoni AS n(20,2)) AS Wl_Cnoni, 
 CAST( Wname.Wl_Nien AS n(20,2)) AS Wl_Nien, 
 CAST( Wname.Wl_Nieco AS n(20,2)) AS Wl_Nieco, 
 CAST( Wname.Wl_Compee AS n(20,2)) AS Wl_Compee, 
 CAST( Wname.Wl_Comper AS n(20,2)) AS Wl_Comper, 
 CAST( Wname.Wl_Pen AS n(20,2)) AS Wl_Pen, 
 CAST( Wname.Wl_Penbl AS n(20,2)) AS Wl_Penbl, 
 CAST( Wname.Wl_Roundcf AS n(20,2)) AS Wl_Roundcf, 
 CAST( Wname.Wn_Ssp1 AS n(20,2)) AS Wn_Ssp1, 
 CAST( Wname.Wn_Ssp2 AS n(20,2)) AS Wn_Ssp2, 
 CAST( Wname.Wn_Ssp3 AS n(20,2)) AS Wn_Ssp3, 
 CAST( Wname.Wn_Ssp4 AS n(20,2)) AS Wn_Ssp4, 
 CAST( Wname.Wn_Ssp5 AS n(20,2)) AS Wn_Ssp5, 
 CAST( Wname.Wn_Ssp6 AS n(20,2)) AS Wn_Ssp6, 
 CAST( Wname.Wn_Ssp7 AS n(20,2)) AS Wn_Ssp7, 
 CAST( Wname.Wn_Ssp8 AS n(20,2)) AS Wn_Ssp8, 
Wname.Wn_Ssprate, 
...
FROM Wname Wname) E1

虽然您可能无法选择数据库,但您可以选择 Entity Framework 吗?我发现使用 Dapper 更适合这种情况,并且可以让您对查询进行低级控制。

sql 语句可能超过 8000+ 限制的原因有很多。作为 VFP EF Provider 的作者,鉴于 VFP 和 Entity Framework 之间的各种限制,我已经尝试尽可能减少 sql 语句。但是 240 个字段没有太多回旋余地。就我个人而言,我会接受 Cetin Basoz 的建议,即通过创建多个 类 来将其视为多个 table,这些 类 代表 table 到 trim 的一部分 sql 语句。或者,您可以使用 LINQ Select 操作只提供字段的子集。那应该为您减少语句,使其不超过 8000+ 限制。

(取消对你的 linq 语句的假设,因为它没有显示......) 如果您确实需要所有列,那么您可能想尝试在仅获取主键的查询和使用主键 return 所有字段的查询之间分解查询。这可能对你有用。

我自己的回答:在处理了一段时间后,我发现 tables 以只读方式添加到 EDMX 模型中。这意味着它是 selecting 来自 select 语句,这是多余的,并且膨胀了 select 语句的大小。当我手动编辑 EDMX 文件并强制其将 table 视为可读写时,问题消失了。

此外,在 Tom 的建议下,我开始更好地欣赏代码优先方法。我完全取消了 EDMX 模型。我发现这更容易管理,因为我通过模型的 class 属性上的属性控制每个字段的处理方式。使用代码优先,我对上下文 classes 的自定义不可能被覆盖;这对我来说是完美的,因为我需要自定义构造函数并覆盖 SaveChanges 和其他方法。