Сохранять вычисленное свойство с помощью Entity Framework Core - PullRequest
2 голосов
/ 26 сентября 2019

Я попытаюсь проиллюстрировать свой вопрос на упрощенном примере: представьте, что у меня есть сущность домена, подобная этой:

public class Box
{
    public int Id { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public int Depth { get; set; }
    public int Volume => Height * Width * Depth;
}

Где я делаю расчет (объем) на основе любого другого свойства.Теперь скажите, что я хочу сохранить этот класс с помощью Entity Framework Core.Можно ли как-нибудь заставить ядро ​​EF сохранить текущее значение Volume в своем собственном столбце, когда я сохраню сущность?

Это мой основной вопрос.Мне не разрешено делиться своим реальным кодом, но вот более подробная информация о моем реальном объекте (назовем его «Box»):

  • My Box имеет 18 свойств, из которых6 являются коллекциями дочерних сущностей, определяющих отношения один-ко-многим с ними, так что вы можете назвать это совокупным корнем.
  • Каждое свойство, включая коллекции дочерних объектов, вносят вклад в «общий итог», назовем его «объем», который отображается как публичное свойство.Всякий раз, когда свойство изменяется или добавляется или удаляется дочерняя сущность, объем будет меняться.
  • На мой взгляд, мне нужно перечислить все ящики, но мне нужно только показать 5 свойств, одно из которых являетсятом, поэтому я хотел бы хранить его в поле базы данных каждый раз, когда сохраняю сущность.

Некоторые идеи о том, как решить эту проблему:

  1. Полностью увлажните каждую коробку и вычислите объем для каждой, а затем спроецируйте это в сводку.Это включает в себя объединение всех семи таблиц для каждого блока с подобъектами, выполнение расчета для каждого блока и проецирование на модели упрощенного представления.Мне просто кажется, что получить число, которое я знал во время сохранения, очень сложно.
  2. Создать «постоянный DTO» для Box и всех дочерних объектов, а затем просто отобразить результат Volume наавто-свойство тома на dto при хранении.Это также кажется большой нагрузкой на хранение только одного числа, и это также, кажется, находится в полном противоречии с тем, как EF должен работать.Я просто хочу сохранить свои сущности.
  3. Я мог бы сделать правильный OO на Box и создать частные поля и правильные установщики для каждого свойства, которое обновляет поле частного тома при каждом вызове установщика.Это также включает в себя методы написания на Box для управления всеми коллекциями дочерних объектов и представления их как коллекции только для чтения.Это может привести к большому количеству служебных личных полей и дублированию кода на каждом сеттере, но кажется более «разумным», чем приведенные выше варианты.
  4. Я мог бы превратить Volume в метод CalculateVolume () и создать Volume-property, используя свободный API, а затем заполните это свойство в переопределении SaveChanges () для контекста.Но переопределение SaveChanges - это тот тип EF gung-ho, который мне неудобно делать.
  5. Я мог бы примерно так:
public class Box
{
    public int Id { get; set; }
    public int Height { get; set; }
    public int Width { get; set; }
    public int Depth { get; set; }
    public int Volume {
        get => CalculateVolume(); 
        private set => _volume = value; }
    private int _volume;
    private int CalculateVolume() => Height * Width * Depth;
}

Который, кажется, делает то, что яхочу, но по какой-то причине хочется обманывать и загрязнять мой домен.Также я не уверен, что это на самом деле работает во всех случаях, но это мое предпочтительное решение на момент написания.

Я бы предпочел иметь возможность просто настроить это, используя свободный API.Я заметил PropertyBuilder.ValueGeneratedOnAdd () - описание метода говорит: «Значение может быть сгенерировано генератором значений на стороне клиента или может быть сгенерировано базой данных как часть сохранения сущности.», Но я не могу найти никаких примеровгенерация значений на стороне клиента.

Любая разумная обратная связь приветствуется.

РЕДАКТИРОВАТЬ: Просто чтобы уточнить: Фактический расчет довольно сложен и использует значения из 7 различных таблиц.Существует также взвешивание каждого участвующего свойства.Пример Box в начале слишком упрощен и только для пояснения.Достаточно сказать, мне нужно сохранить расчет в моем коде.Я просто хочу сохранить результат.

1 Ответ

1 голос
/ 26 сентября 2019

Вы можете использовать свободный API для вычисления на сервере SQL

class MyContext : DbContext
{
    public DbSet<Box> Box { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Box>()
            .Property(p => p.Volume)
            .HasComputedColumnSql("[Height] * [Width] * [Depth]");
    }
}
...