繁体   English   中英

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

[英]Entity Framework vs Oracle nested query limitations

我有以下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; }
}

当我尝试此查询时:

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);

...或此等效查询(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语句存在问题,因此出现异常。 具体来说,它试图在多嵌套子查询使用声明的标识符阿尔法表,作为描述在这里 ,Oracle不会映射标识符超过1级深。

我疯了,还是遗漏了一些明显的东西? Oracle是否真的发布了一个EF提供程序,它将生成查询,他们自己的数据库无法运行以获得合理的(尽管不可忽视的)查询?

是否有可以设置的配置选项(在数据库中或在EF中)有助于此? 是否有一些策略可用于以不同方式构建查询或拆分它们以解决此问题(通过将单个往返转换为多个来实现坦克性能)?

请注意,我自己可以编写一个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)

我想使用EF创建一个模块化系统,允许不知道任何SQL的用户使用我提供的构建块构建自己的查询; 每个“块”都有一个Expression<Func<Model, bool>> ,它可以被打成一个Where子句链来构建查询。 这一点的重点是避免为用户可能想要查找的所有内容编写实际的SQL查询。

问题不在于Oracle。 EF Provider for Oracle生成EF要求的小块查询。 在这方面,EF效率不高。
无论如何,在这种情况下,你有两种不同的方法。
你可以尝试简化查询(就像你写的那样)。
另一种方法是使用从SQL查询(而不是LINQ查询)开始的不同映射器来实现实体。 我知道Dapper但实际上只是为了只读目的而且有其他一些限制。

我不知道最糟糕的是什么......

暂无
暂无

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

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