Как мне инкапсулировать коллекцию в объект «сложного типа» с Ef Core (пример включен) - PullRequest
2 голосов
/ 17 апреля 2019

Я хотел бы отобразить в Ef Core сложный тип (другими словами, тип, не связанный непосредственно с таблицей), который содержит список объектов, которые непосредственно отображаются в таблицу.

Рассмотрим следующий пример ниже, где вы обнаружите, что логика Diary (из которой я сейчас только показываю AddEntry ) отделена от класса Request, так как это не имеет значения быть там.

У меня нет проблем с использованием .OwnsOne в Ef Core при использовании более простых типов, где данные хранятся в одной и той же таблице (например, здесь это будет в таблице запросов); но я не имею ни малейшего представления или понятия, как бы я отобразил в OnConfiguring эту ситуацию.

  • C # модель:
public class Request : DbEntity {
   public Diary { get; set; }
}

public class DiaryEntry : DbEntity {
   public DateTimeOffset Timestamp { get; set; }
   public Request Request { get; set; }
   public string Message { get; set; }   
}

public class Diary {
   private readonly List<DiaryEntry> _entries = new List<DiaryEntry>();
   public Request Request { get; set; }
   public IEnumerable<DiaryEntry> Entries => _entries;
   public Diary AddEntry(DiaryEntry diaryEntry) {
      if(diaryEntry != null)
         _entries.Add(diaryEntry);
      return this;
   }
}
  • Структура SQL
    • Requests - это таблица, которая отображается в EfCore на Entity Request
    • DiaryEntries - это таблица, которая существует в EfCore и косвенно сопоставляется с DbSet с запросом как "HasOne", так что она имеет отношение.
    • Таблица «Дневник» не существует, это «сложный тип», который инкапсулирует логику, поэтому мне не приходится иметь дело с ней в типе «Запрос» в C #

1 Ответ

4 голосов
/ 23 апреля 2019

Я не верю, что подобное поддерживается в Entity Framework, поскольку сложные типы предназначены для поддержки организации свойств одной таблицы в связанные классы без реляционных таблиц. В вашем случае вы хотели бы взять реляционные таблицы и отобразить промежуточный класс, чтобы избежать правил управления дочерней коллекцией в родительском классе.

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

Например:

[Table("Requests")]
public class Request
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int RequestId { get; set; }
    public string Name { get; set; }

    public virtual IEnumerable<DiaryEntry> Diary { get; protected set; } = new List<DiaryEntry>();
}

[Table("DiaryEntries")]
public class DiaryEntry
{
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int DiaryEntryId { get; set; }
    public string Value { get; set; }

    public virtual Request Request { get; set; }
}

Здесь мы представляем Дневник как IEnumerable<DiaryEntry>, поэтому потребители объекта не могут изменять коллекцию и т. Д. Оттуда функциональность дневника может управляться расширениями:

public static class DiaryExtensions
{
    public static DiaryEntry AddEntry(this IEnumerable<DiaryEntry> diary, DiaryEntry newEntry)
    {
        ICollection<DiaryEntry> diaryList = (ICollection<DiaryEntry>)diary;
        if (newEntry != null)
            diaryList.Add(newEntry);

        return newEntry;
    }
}

Лично, хотя у меня была бы эта логика в Запросе, поскольку записи в дневнике связаны с запросом. Чтобы отделить логику, специфичную для дневника, я бы использовал частичные классы, но сохраняя ответственность за поддерживаемое поведение в классе, который их содержит.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...