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

时间:2015-06-08 20:05:10

标签: c# oracle entity-framework odp.net

我有以下Code First模型(虽然事实上我只是使用EF来访问现有数据库的子集;为简洁起见,此示例中省略了Table& Column属性):

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-&gt; 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表的声明标识符,并且如here所述,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的用户使用我提供的构建块构建自己的查询;每个&#34;块&#34;会有一个Expression<Func<Model, bool>>可以被打成一个Where子句链来构建查询。这一点的重点是避免为用户可能想要查找的所有内容编写实际的SQL查询。

1 个答案:

答案 0 :(得分:0)

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

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