EF6是如何知道派生类型的?

本文关键字:类型 派生 何知道 EF6 | 更新日期: 2023-09-27 18:09:57

我使用实体框架6与每类型表继承方法。

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

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]可以是IntConfigurationKey, keys[1]可以是StringConfigurationKey型。我可以安全地强制转换它并访问派生类型的属性。
这是一个伟大的功能,我喜欢它,但我想知道它是如何工作的,以便在未来保持这个功能。它是使用enum还是在所有表中寻找具有相同ID的实体?

EF6是如何知道派生类型的?

它是使用enum还是在所有表中寻找具有相同ID的实体?

对于TPT策略,它确实对所有相关的表使用LEFT OUTER JOIN s来确定派生类型(和数据)。没有使用标识符列或枚举。

您可以通过打开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] 

详细说明可以在EF代码优先的继承:第2部分-每个类型的表(TPT)中找到。

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

这就是为什么你会看到所有从不同具体类型返回的数据

要了解更多关于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