简体   繁体   English

实体框架与Oracle嵌套查询限制

[英]Entity Framework vs Oracle nested query limitations

I have the following Code First models (though in fact I'm just using EF to access a subset of an existing database; Table & Column attributes have been omitted from this example for brevity): 我有以下Code First模型(虽然实际上我只是使用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 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; }
}

When I attempt this query: 当我尝试此查询时:

var result = context.Alphas.Where(a => a.State == AlphaState.Good)
                           .Where(a => a.Deleted != "Y")
                           .Where(a => a.Bravos.SelectMany(b => b.Charlies)
                                               .Where(c => c.Deleted != "Y")
                                               .Where(c => c.Delta.Echoes.Any())
                                               .OrderByDescending(c => c.CreatedAt).Take(1)
                                               .Any(c => c.Delta.Echoes.Any(e => e.Type == EchoType.Two)))
                           .Select(a => a.AlphaIndex);

...or this equivalent query (B->A and D->E are 1:0..1 relations): ...或此等效查询(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);

...I get an exception because of a problem in the SQL statement that is generated. ...由于生成的SQL语句存在问题,因此出现异常。 Specifically, it's trying to use the declared identifier for the Alpha table in a multi-nested subquery, and, as described here , Oracle doesn't map identifiers more than 1 level deep. 具体来说,它试图在多嵌套子查询使用声明的标识符阿尔法表,作为描述在这里 ,Oracle不会映射标识符超过1级深。

Am I crazy, or missing something obvious? 我疯了,还是遗漏了一些明显的东西? Did Oracle seriously ship an EF provider that will generate queries their own database can't run for reasonable (though admittedly not trivial) queries? Oracle是否真的发布了一个EF提供程序,它将生成查询,他们自己的数据库无法运行以获得合理的(尽管不可忽视的)查询?

Is there a configuration option that can be set (in the database or in EF) that will help with this? 是否有可以设置的配置选项(在数据库中或在EF中)有助于此? Is there some strategy I can use to build queries differently or split them up that will solve this problem (without tanking performance by turning a single round-trip into many)? 是否有一些策略可用于以不同方式构建查询或拆分它们以解决此问题(通过将单个往返转换为多个来实现坦克性能)?

Note that I can write a SQL statement myself that will get the same information: 请注意,我自己可以编写一个SQL语句来获取相同的信息:

select A.alpha_index
from ALPHA A
inner join BRAVO B on B.alpha_index = A.alpha_index
inner join CHARLIE C on C.bravo_index = B.bravo_index
inner join ECHO E on E.delta_index = D.delta_index
where (A.deleted is null or A.deleted <> 'Y')
  and A.state = 'G'
  and E.type = 2
  and C.created_at = (select max(C2.created_at)
                      from CHARLIE C2
                      inner join ECHO E2 on E2.delta_index = C2.delta_index
                      where (C2.deleted is null or C2.deleted <> 'Y')
                        and C2.bravo_index = C.bravo_index)

I want to use EF to make a modular system that allows users who don't know any SQL to build their own queries using building blocks I provide; 我想使用EF创建一个模块化系统,允许不知道任何SQL的用户使用我提供的构建块构建自己的查询; each "block" would have an Expression<Func<Model, bool>> that can be slapped into a chain of Where clauses to build the query. 每个“块”都有一个Expression<Func<Model, bool>> ,它可以被打成一个Where子句链来构建查询。 The whole point of this is to avoid having to write actual SQL queries for everything users might want to look for. 这一点的重点是避免为用户可能想要查找的所有内容编写实际的SQL查询。

The problem is not really Oracle. 问题不在于Oracle。 EF Provider for Oracle generates small pieces of queries that EF ask to it. EF Provider for Oracle生成EF要求的小块查询。 EF, in this, is not efficient. 在这方面,EF效率不高。
Anyway, in this case you have 2 different approaches. 无论如何,在这种情况下,你有两种不同的方法。
You could try to simplify the query (like you wrote). 你可以尝试简化查询(就像你写的那样)。
The other approach is to use a different mapper that starts from SQL query (not LINQ queries) to materialize entities. 另一种方法是使用从SQL查询(而不是LINQ查询)开始的不同映射器来实现实体。 I know Dapper but actually is good only for read only purpose and has several other limitations. 我知道Dapper但实际上只是为了只读目的而且有其他一些限制。

I don't know what is the worst... 我不知道最糟糕的是什么......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM