【问题标题】:Is it possible to force EF (Code First) to ignore derived types when constructing the final SQL构造最终 SQL 时是否可以强制 EF(代码优先)忽略派生类型
【发布时间】:2012-12-12 19:25:50
【问题描述】:

如果我有这个作为我的 TPT 模型:

public class Foo
{
    public Int32 Id { get; set; }
    public string Text { get; set;  }
}

[Table("Bars")]
public class Bar : Foo
{
    public string MoreText { get; set; }
}

还有一个像这样的派生 DbContext:

public class MyContext : DbContext
{
    public DbSet<Foo> Foos { get; set; }
    public DbSet<Bar> Bars { get; set; }
}

然后,当我对 Foo 执行查询时,最终的 SQL 将包含到 Bar 的外部连接。

例如:

uisng(var context = new MyContext())
{
    Console.WriteLine(context.Foos.ToString());
}

将导致这个作为最终的 SQL 语句

SELECT
CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN
'0X' ELSE '0X0X' END AS [C1],
[Extent1].[Id] AS [Id],
[Extent1].[Text] AS [Text],
CASE WHEN ( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) THEN
CAST(NULL AS varchar(1)) ELSE [Project1].[MoreText] END AS [C2]
FROM  [dbo].[Foos] AS [Extent1]
LEFT OUTER JOIN  (SELECT
        [Extent2].[Id] AS [Id],
        [Extent2].[MoreText] AS [MoreText],
        cast(1 as bit) AS [C1]
        FROM [dbo].[Bars] AS [Extent2] ) AS [Project1] ON [Extent1].[Id] = [Proj
ect1].[Id]

我确实明白为什么 --- 这样做可以让我做类似的事情:

foreach(var x in context.Foos)
{
    if(x is Bar) Console.WriteLine("Impressive");
    else Console.WriteLine("Not so much");
}

但是,您可以想象这种对基类的查询会很快导致 SQL Server 处理的噩梦般的查询。因此问题。

是否可以通知 Linq to EF 5.0 它应该只带回基本类型而不是派生类型。从而使最终的 SQL 更简单?

【问题讨论】:

  • 您是否尝试过使用OfType - 例如context.Foos.OfType&lt;Foo&gt;()?我不确定它是否会使生成的 SQL 语句更简单...

标签: entity-framework ef-code-first entity-framework-5


【解决方案1】:

不适用于 Linq to Entity。 Linq to entity 提供OfType,但它使用.NET 规则进行类型继承,因此如果您使用OfType&lt;Foo&gt;,您仍将同时获得FooBar 实例,因为Bar 的类型为Foo

Entity SQL(在代码优先和 DbContext API 中不可用 - 您必须通过 ObjectContext API 访问它)更强大,因为它不依赖于 Linq 提供的有限功能。它提供了构造OFTYPE ONLY,它只能返回Foo 的实例,但我相信它不会使查询更简单,因为要找到哪些类型只有Foo 而不是Bar,它仍然必须进行连接。如果您希望获得 Foo 的实例,即使对象是 Bar,您也无法使用 EF 实现 - 实体类型是不可变的。您不能更改查询中的类型。

使用OfType 和Linq 的最简单解决方法是将Foo 定义为抽象并添加额外的派生类型。您将始终使用OfType 查询一个真实类型,并且它应该确保您没有与不必要的表进行连接。

【讨论】:

  • 我不确定如果它是抽象的,我可以查询 Foo 将如何工作。
  • 这就是重点——您不会查询Foo,而是查询派生类型。如果你只想要来自Foo 的属性,而你实际上并不关心真正的类型是什么,那么你必须使用投影。
猜你喜欢
  • 2012-08-21
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
  • 2017-05-25
  • 2023-03-06
  • 1970-01-01
  • 2020-03-08
  • 2017-12-24
相关资源
最近更新 更多