EF6 如何知道派生类型?

How does EF6 know derived type?

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

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

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

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

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

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

要阅读有关 EF 中继承的更多信息,请遵循此 link 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

Does it use enum or does it look for an entity with the same ID across all tables?

对于 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)