C# 实体框架与Oracle嵌套查询限制
我有以下代码优先模型,尽管事实上我只是使用EF访问现有数据库的子集;为了简洁起见,此示例中省略了表和列属性:C# 实体框架与Oracle嵌套查询限制,c#,oracle,entity-framework,odp.net,C#,Oracle,Entity Framework,Odp.net,我有以下代码优先模型,尽管事实上我只是使用EF访问现有数据库的子集;为了简洁起见,此示例中省略了表和列属性: public enum AlphaState { Unknown = '\0', Good = 'G', Bad = 'B' } public class Alpha { [Key] public long AlphaIndex { get; set; } public string Deleted { get; set; } public Alpha
public enum AlphaState { Unknown = '\0', Good = 'G', Bad = 'B' }
public class Alpha
{
[Key]
public long AlphaIndex { get; set; }
public string Deleted { get; set; }
public AlphaState State { get; set; }
[InverseProperty("Alpha")]
public ICollection<Bravo> Bravos { get; set; }
}
public class Bravo
{
[Key]
public long BravoIndex { get; set; }
[ForeignKey("Alpha")]
public long? AlphaIndex { get; set; }
public virtual Alpha Alpha { get; set; }
[InverseProperty("Bravo")]
public ICollection<Charlie> Charlies { get; set; }
}
public class Charlie
{
[Key]
public int CharlieIndex { get; set; }
public string Deleted { get; set; }
public DateTime CreatedAt { get; set; }
[ForeignKey("Bravo")]
public long BravoIndex { get; set; }
public virtual Bravo Bravo { get; set; }
[ForeignKey("Delta")]
public long DeltaIndex { get; set; }
public virtual Delta Delta { get; set; }
[InverseProperty("Charlie")]
public virtual ICollection<Delta> AllDeltas { get; set; }
}
public class Delta
{
[Key]
public long DeltaIndex { get; set; }
[ForeignKey("Charlie")]
public long CharlieIndex { get; set; }
public virtual Charlie Charlie { get; set; }
[InverseProperty("Delta")] // actually a 1:0..1 relationship
public ICollection<Echo> Echoes { get; set; }
}
public enum EchoType { Unknown = 0, One = 1, Two = 2, Three = 3 }
public class Echo
{
[Key]
public int EchoIndex { get; set; }
public EchoType Type { get; set; }
[ForeignKey("Delta")]
public long DeltaIndex { get; set; }
public virtual Delta Delta { get; set; }
}
…或此等效查询B->A和D->E是1:0..1关系:
var result = context.Bravos.Where(b => b.Alpha != null)
.Where(b => b.Alpha.State == AlphaState.Good)
.Where(b => b.Alpha.Deleted != "Y")
.Where(b => b.Charlies.Where(c => c.Deleted != "Y")
.Where(c => c.Delta.Echoes.Any())
.OrderByDescending(c => c.CreatedAt)
.FirstOrDefault().Delta.Echoes
.Any(e => e.Type == EchoType.Two))
.Select(b => b.AlphaIndex);
…由于生成的SQL语句中存在问题,因此出现异常。具体来说,它试图在多嵌套子查询中使用Alpha表的声明标识符,并且,如前所述,Oracle映射标识符的深度不超过1级
我是疯了,还是错过了一些明显的东西?Oracle是否真的提供了一个EF提供者,该提供者将生成他们自己的数据库无法运行的合理查询(尽管不可否认不是琐碎的查询)
是否有可以在数据库或EF中设置的配置选项有助于实现这一点?我是否可以使用某种策略以不同的方式构建查询或将查询拆分,从而在不降低性能的情况下,通过将单个往返转换为多个查询来解决此问题
请注意,我可以自己编写一个SQL语句,以获得相同的信息:
选择A.alpha_索引
来自阿尔法A
B.alpha_索引=A.alpha_索引上的内部连接BRAVO B
C.bravo_索引=B.bravo_索引上的内部连接C
E.delta_索引上的内部连接回声E=D.delta_索引
其中A.deleted为null或A.deleted为“Y”
和A.state='G'
E.type=2
和C.created_at=选择maxC2.created_at
查理C2
E2上的内部联接回显E2.delta_索引=C2.delta_索引
其中C2.deleted为空或C2.deleted为“Y”
和C2.bravo_指数=C.bravo_指数
我想使用EF来创建一个模块化系统,允许不懂SQL的用户使用我提供的构建块构建自己的查询;每个块都有一个表达式,可以将其插入Where子句链中以构建查询。这样做的全部目的是避免为用户可能想要查找的所有内容编写实际的SQL查询。问题并不真正是Oracle。EF Provider for Oracle生成EF向其请求的小部分查询。在这方面,EF是没有效率的。 无论如何,在这种情况下,您有两种不同的方法。 您可以尝试像编写的那样简化查询。 另一种方法是使用不同的映射器(从SQL查询而不是LINQ查询开始)来具体化实体。我知道Dapper,但实际上它只适用于只读目的,并且还有其他一些限制
我不知道最糟糕的是什么…我在Oracle EF提供程序中遇到过类似的问题,生成的SQL不符合要求。我基本上正在原型化一种结构,允许不懂SQL的用户使用构建块UI构建查询,因此只读对我来说不是问题。Dapper是否允许我结合多种Where条件?在EF中,我会为每个构建块保存一个表达式,我能用Dapper做类似的事情吗?另外,它与SQL Server一起工作吗?@ObliviousSage:Dapper与SQL Server一起工作!事实上,它是由我们在SO的友好主机编写的,用于连接SQL Server。@Gabe进一步调查后,我不认为Dapper是我想要的:它是ORM的错误的一半。它不会为您编写查询,它只是将结果映射到POCO中;一、 另一方面,我们需要一些相反的东西。我想要一些可以从我可以保存的一堆可互换的片段中为我构建查询的东西,但我实际上不需要POCOs中的结果。@在这种情况下,健忘Sage不适合Dapper。有几个映射器允许linq查询,但我只使用了NHibernate,因为几个月前我使用了EF,通常NHibernate使查询更简单,但由于NH的限制,您需要经常具体化查询。好的,我也会研究NHibernate。谢谢你,布比!
var result = context.Bravos.Where(b => b.Alpha != null)
.Where(b => b.Alpha.State == AlphaState.Good)
.Where(b => b.Alpha.Deleted != "Y")
.Where(b => b.Charlies.Where(c => c.Deleted != "Y")
.Where(c => c.Delta.Echoes.Any())
.OrderByDescending(c => c.CreatedAt)
.FirstOrDefault().Delta.Echoes
.Any(e => e.Type == EchoType.Two))
.Select(b => b.AlphaIndex);