简体   繁体   中英

How does EF6 know derived type?

I use Entity Framework 6 with Table-Per-Type inheritance approach.

Tables look like this (just an example):

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

and the following classes structure:

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; }
}    

No other configurations and model builder mappings are made.

Now, when I do the following query:

var keys = context.ConfigurationKeys.ToArray();

Entity Framework returns an array of derived types .
Ie, keys[0] may be IntConfigurationKey and keys[1] may be of type StringConfigurationKey . I can safely cast it and access properties of derived types.
It is a great feature and I love it, but I would like to know how it works in order to maintain this functionality in future.
Does it use enum or does it look for an entity with the same ID across all tables?

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

With TPT strategy it does use LEFT OUTER JOIN s to all related tables for determining the derived type (and data). No discriminator column or your enum is used.

You can see that by looking at the generated SQL by either turning on the EF logging or using query.ToString() . So both

var sql = context.ConfigurationKeys.ToString();

or

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

will show something like this:

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] 

Detail explanation can be found in Inheritance with EF Code First: Part 2 – Table per Type (TPT) .

By default, EF uses the Table per Hierarchy strategy to create the database tables, so, your classes will be mapped to a single table and there will be a discriminator column.

This is why you see all the data returned from different concrete types

To read more about the inheritance in EF, follow this 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM