Да, вы можете использовать наследование в Entity Framework. Однако базы данных обычно не поддерживают наследование. В наследования баз данных издеваются. Для изнашивания наследования используются несколько стратегий.
Предположим, у вас есть три класса:
public class MyBaseItem {...}
public class MyDerived1Item : MyBaseItem {...}
public class MyDerived2Item : MyBaseItem {...}
Стратегия таблица на конкретный класс (TPC) я использую этот наиболее часто, если мне не нужно создавать MyBaseItem объекты, только MyDerived1Items или MyDerived2Items. Чтобы предотвратить случайное создание объектов MyBaseItem, я объявляю аннотацию MyBaseItem.
В базе данных будут две таблицы: одна с MyDerived1Items и одна с MyDerived2Itemss. Обе таблицы будут иметь столбцы для всех свойств MyBaseItem.
Fluent API используется, чтобы сообщить разработчику базы данных, что эта стратегия используется.
public MyDbContext : DbContext
{
public DbSet<MyDerived1Item> MyDerived1Items {get; set;}
public DbSet<MyDerived2Item> MyDerived2Items {get; set;}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<MyDerived1Item>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("MyDerived1Items");
});
modelBuilder.Entity<MyDerived2Item>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("MyDerived2Items");
});
}
}
Добавление/изменение/удаление элементов в базе данных всегда будет означать доступ к одной таблице, если если вы хотите сделать что-то со свойствами MyBaseItems всех производных элементов. В этом случае вам придется отливать элементы каждой производной таблицы в MyBaseItem и Concat все производные таблицы, например:
IQueryable<MyBaseItem> someBaseItems =
dbContext.MyDerived1Items.Where(...).Cast<MyBaseItem>()
.Concat(dbContext.MyDerived2Items.Where(...).Cast<MyBaseItem>();
Легко позже добавить таблицу MyDerived3Items. Таблицы MyDerived1Items и MyDerived2Items не должны будут меняться.
Однако добавление одного свойства в MyBaseItem означает добавление поля ко всем таблицам производных классов.
Стратегия Таблица для каждого типа (TPT)
Создать три таблицы. Один стол для каждого типа. Таблицы с производными элементами имеют внешний ключ к таблице с базовыми элементами.
Если вы создадите объект MyDerived1Item, объект будет помещен в две таблицы. Свойства MyBaseItem базового класса будут в таблице MyBaseItems, а свойства MyDerived1Item будут в таблице MyDerived1Items вместе с внешним ключом к соответствующему элементу в MyBaseItem.
Я не предпочитаю этот метод, потому что он очень похож на отношение «один ко многим». В базе данных можно было бы иметь один базовый элемент с двумя производными элементами, имеющими один и тот же внешний ключ, который не является тем, что вы намеревались. Я не уверен, что вы можете предотвратить добавление такого объекта в базу данных.
Добавление/поиск/изменение/удаление элементов всегда подразумевает использование двух таблиц, что делает эти действия медленнее.
Однако преимущество этого метода заключается в том, что вы можете создавать MyBaseItems. Поэтому, если вам нужно это сделать, рассмотрите эту стратегию.
How to implement Table Per Type (TPT)
Таблица на иерархии (TPH)
Эта стратегия по умолчанию для структуры объекта.
В базе данных будет одна таблица, содержащая все свойства MyBaseItem, MyDerived1Item и MyDerived2Item. Не используемые столбцы имеют значение NULL. Если MyDerived1Items почти такие же, как MyDerived2Items, то не будет много лишних столбцов. Однако, если эти два класса сильно отличаются друг от друга, тогда будет множество столбцов, имеющих значение null.
Как вы будете иметь одну таблицу вы будете иметь один DbSet:
public class MyDbContext: DbContext
{
public DbSet<MyBaseItem> MyItems { get; set; }
}
Поскольку это стратегия по умолчанию, не свободно API не требуется.
Если вам нужен запрос, который использует только основные свойства:
IQueryable<MyBaseItem> baseItems = dbContext.MyItems
.Where(...);
Если вам нужны только MyDerived1Items:
IQueryable<MyDerived1Item> myItems = dbContext.MyItems
.OfType<MyDerived1Items>()
.Where(...);
Рассмотрим эту стратегию, если вы ожидаете много запросов только с базовыми свойствами , так как это только доступ к одной таблице. Пересмотрите его, если ваши производные классы сильно отличаются друг от друга.
Дайте нам попробовать и дайте нам знать! – Maarten
@Maarten Я знаю, что могу попробовать посмотреть, работает ли это. Я боюсь, что это может сработать, но быть плохим или неправильным и сделать неприятности для меня в последующих частях проекта. –
Я бы предложил прочитать [Наследование с EF Code First] (https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-1-table- per-hierarchy-tph). –