Ваш объектный график не совсем понятен.Похоже, Dog
и Person
просто связаны с Item
, но на основании вашего описания и краткого примера кода может показаться, что они на самом деле типы элементов.Если это так, вы должны использовать стратегию наследования, а не композицию.
public class Item
public class Dog : Item
public class Person : Item
По умолчанию EF будет обрабатывать наследование с помощью стратегии TPH (таблица на иерархию), которая здесь не подходит.Вместо этого я думаю, что вам понадобится TPT (таблица для каждого типа), что может быть достигнуто с помощью атрибута Table
в производном классе:
[Table("Dogs")]
public class Dog : Item
[Table("Persons")]
public class Person :
Что это будет делать, это создать три таблицы,Dogs
, Persons
и Items
.Любые данные, общие для всех предметов, независимо от того, собака это или человек, очевидно, попадут в ваш класс Item
и окажутся в таблице Items
.Внешние ключи будут добавлены в таблицу Dogs
и Persons
, указывая на таблицу Items
.Например, когда вы извлекаете Dog
, EF автоматически присоединяется к соответствующей записи в Items
для создания полного Dog
.
. Это дает вам некоторые особые возможности в ваших запросах.Вы можете получить все элементы независимо от их типа, конечно же, с помощью _context.Items
, но вы также можете иметь отдельные DbSet
для Dog
и Person
, что позволит вам запрашивать их независимо: например, _context.Dogs
.Даже без явного DbSet
вы можете использовать общий метод Set<TEntity>
: _context.Set<Dog>()
.Кроме того, вы можете использовать OfType<TEntity>
для фильтрации набора Items
: _context.Items.OfType<Dog>()
.
Наконец, даже если вы просто извлекаете Items
, EF по-прежнему отслеживает, какой конечный тип у каждого Item
, какойозначает, что вы можете делать такие вещи, как сопоставление с образцом:
if (item is Dog dog)
{
// `dog` is now a variable in this scope of your `item` downcast to `Dog`
}
Или в операторах switch:
switch (item)
{
case Dog dog:
// do something with `dog`
break;
case Person person:
// do something `person`
break;
default:
// do something with generic items (`item`)
break;
}
EDIT
Я понял, что только яссылался на следующее, а не заявляя явно.Поскольку Dog
и Person
- это совершенно разные таблицы в TPT, вы можете определить там совершенно разные отношения.Например, Dog
может иметь отношение с DogStatus
, не затрагивая ничего, что происходит с Person
.Технически вы все еще можете сделать это даже с TPH, но в итоге у вас будет куча внешних ключей, которые можно обнулять, в таблице Items
, и это будет просто беспорядок, а также нарушит нормализацию.