Использование отфильтрованных строк как части DBContext с производным классом

Я хочу использовать наследование классов для фильтрации строк в базе данных, что не является абсолютно нормальным и реляционным. Существует таблица entities, сопоставленная с моделью Entity через EF Core:

[Table("entities")]
public class Entity
{
    public int Id { get; set; }
    public string Type { get; set; }
}

Type - это некоторая строка, которая может быть "A" или "B", например.

Я хочу указать класс EntityA : Entity для сущностей с типом A и соответственно для B:

public class EntityA : Entity
{
    // some unique A properties
}

public class EntityB : Entity
{
    // some unique B properties
}

В основном мой DBContext выглядит так

public class ApplicationContext : DbContext
{
    public DbSet<Entity> Entities { get; set; }

    // ...
}

Могу ли я определить EntitiesA и EntitiesB в своем DBContext, используя фильтрацию по типу?

Я хотел написать это хотя бы по-дурацки:

public List<EntityA> EntitiesA
{
    get
    {
        return Entity.Where(x => x.Type == "A").ToList();
    }
}

Но есть проблема приведения классов (поскольку код возвращает список, а не список), а также это не похоже на решение в стиле ORM, EntitiesA не является DBSet, загружает запрос автоматически и так далее.


person lenden    schedule 26.02.2020    source источник


Ответы (2)


Хорошо, я нашел, это называется Discriminator в EF Core, кому интересно, можете прочитать здесь: https://docs.microsoft.com/en-us/ef/core/modeling/inheritance

person lenden    schedule 26.02.2020

Я не думаю, что это хорошая идея приводить EntitiesA и EntitiesB к DBContext. Потому что в основном он содержит некоторые знания о предметной области приложения (бизнес-уровень), которые должны быть полностью отделены от вашего DBContext (уровень доступа к данным).

Я предлагаю иметь EntityLoader на бизнес-уровне, который отвечает за загрузку сущностей из БД и возвращает список EntityA или B.

Что касается проблемы приведения классов, вы можете исправить ошибку компиляции с помощью

return Entity.Where(x => x.Type == "A").Select(x => (EntityA)x).ToList();

Однако вы получите ошибку времени выполнения, поскольку тип Entity менее специфичен, чем тип EntityA. Это означает, что вам нужно конвертировать вот так

return Entity.Where(x => x.Type == "A").Select(x => new EntityA(....)).ToList();
person Alex - Tin Le    schedule 26.02.2020
comment
На самом деле это логика уровня данных, а не бизнес-логика. Потому что это внешняя база данных, созданная для cms, которая не имеет ничего общего с приложением asp. Для уровня данных в приложении asp лучше понимать строки из этой таблицы как разные модели, которые должны быть разными таблицами, если мы начинаем с нуля для нашего приложения asp. - person lenden; 27.02.2020
comment
В EF Core Discriminator вам по-прежнему нужна таблица БД для EntityA и таблица БД для EntityB. Но в своем вопросе вы говорите, что для Entity есть только 1 таблица. Я могу неправильно понять ваш вопрос. - person Alex - Tin Le; 27.02.2020
comment
Нет, речь идет об общем столе. Вы можете открыть ссылку из моего ответа - есть даже скриншот с одной таблицей, генерирующей разные сущности - person lenden; 27.02.2020