EF6如何知道派生类型?

时间:2016-10-02 10:31:29

标签: c# entity-framework table-per-type

我使用Entity Framework 6和Table-Per-Type继承方法。

表格看起来像这样(只是一个例子):

ConfigurationKeys
  ID - int, not null, auto increment, primary
  ConfigurationKeyType - int, not null
  Key - varchar(50), not null

StringConfigurationKeys
  ID - int, not null, primary (foreign key to ConfigurationKey.ID)
  StringValue - varchar(50), not null

IntConfigurationKeys
  ID - int, not null, primary (foreign key to ConfigurationKey.ID)
  IntValue - int, not null

以及以下类结构:

public enum ConfigurationKeyType 
{
    StringConfigurationKey = 0,
    IntConfigurationKey = 1
}

[Table("ConfigurationKeys")]
public class ConfigurationKey
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public ConfigurationKeyType ConfigurationKeyType { get; set; }

    public string Key { get; set; }
}

[Table("StringConfigurationKeys")]
public class StringConfigurationKey : ConfigurationKey
{
    public string StringValue { get; set; }
}

[Table("IntConfigurationKeys")]
public class IntConfigurationKey : ConfigurationKey
{
    public int IntValue { get; set; }
}    

没有进行其他配置和模型构建器映射。

现在,当我执行以下查询时:

var keys = context.ConfigurationKeys.ToArray();

实体框架返回派生类型的数组 即,keys[0]可以是IntConfigurationKeykeys[1]可以是StringConfigurationKey类型。我可以安全地转换它并访问派生类型的属性 这是一个很棒的功能,我喜欢它,但我想知道它是如何工作的,以便将来保持这种功能 它是使用枚举还是在所有表中查找具有相同ID的实体?

2 个答案:

答案 0 :(得分:1)

  

它是使用枚举还是在所有表中查找具有相同ID的实体?

使用TPT策略,它会对所有相关表使用LEFT OUTER JOIN来确定派生类型(和数据)。没有使用鉴别器列或您的枚举。

您可以通过打开EF日志记录或使用query.ToString()来查看生成的SQL。所以两者

var sql = context.ConfigurationKeys.ToString();

context.Database.Log = Console.WriteLine;
var keys = context.ConfigurationKeys.ToArray();

会显示如下内容:

SELECT 
    CASE WHEN (( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN '0X' WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)) THEN '0X0X' ELSE '0X1X' END AS [C1], 
    [Extent1].[ID] AS [ID], 
    [Extent1].[ConfigurationKeyType] AS [ConfigurationKeyType], 
    [Extent1].[Key] AS [Key], 
    CASE WHEN (( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN CAST(NULL AS int) WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)) THEN [Project1].[IntValue] END AS [C2], 
    CASE WHEN (( NOT (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL))) AND ( NOT (([Project2].[C1] = 1) AND ([Project2].[C1] IS NOT NULL)))) THEN CAST(NULL AS varchar(1)) WHEN (([Project1].[C1] = 1) AND ([Project1].[C1] IS NOT NULL)) THEN CAST(NULL AS varchar(1)) ELSE [Project2].[StringValue] END AS [C3]
    FROM   [dbo].[ConfigurationKeys] AS [Extent1]
    LEFT OUTER JOIN  (SELECT 
        [Extent2].[ID] AS [ID], 
        [Extent2].[IntValue] AS [IntValue], 
        cast(1 as bit) AS [C1]
        FROM [dbo].[IntConfigurationKeys] AS [Extent2] ) AS [Project1] ON [Extent1].[ID] = [Project1].[ID]
    LEFT OUTER JOIN  (SELECT 
        [Extent3].[ID] AS [ID], 
        [Extent3].[StringValue] AS [StringValue], 
        cast(1 as bit) AS [C1]
        FROM [dbo].[StringConfigurationKeys] AS [Extent3] ) AS [Project2] ON [Extent1].[ID] = [Project2].[ID] 

详细说明可在Inheritance with EF Code First: Part 2 – Table per Type (TPT)中找到。

答案 1 :(得分:0)

默认情况下,EF使用Table per Hierarchy策略来创建数据库表,因此,您的类将映射到单个表,并且将有一个鉴别器列。

这就是您看到从不同具体类型返回的所有数据的原因

要详细了解EF中的继承,请点击此链接https://www.asp.net/mvc/overview/getting-started/getting-started-with-ef-using-mvc/implementing-inheritance-with-the-entity-framework-in-an-asp-net-mvc-application