在构造最终SQL时,是否可以强制EF(代码优先)忽略派生类型

时间:2012-12-12 19:25:51

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

如果我将此作为我的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到EF 5.0它应该只返回基类型而不是派生类型。因此使最终的SQL更简单?

1 个答案:

答案 0 :(得分:2)

不是Linq to Entities。 Linq to entities提供OfType但它使用.NET规则进行类型继承,因此如果您使用OfType<Foo>,您仍然会获得FooBar个实例,因为Bar属于Foo类型。

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

使用OfType和Linq的最简单的解决方法是将Foo定义为抽象并添加其他派生类型。您将始终使用OfType查询实际类型,并确保您没有不必要的表的连接。