Обложка канала

.NET Разработчик

Опытный разработчик не так давно зашёл в .Net и поставил цель получить сертификат Microsoft. Свой ежедневный прогресс он описывает на канале .Net Разработчик. Заметки об изученном материале, советы по повышению производительности и поддержке мотивации, ин

.NET Разработчик

4 года назад
Открыть в
День 1290. #ЗаметкиНаПолях Хранение Динамических Данных с Помощью EF Core. Окончание Начало 2. Хранение пользовательских данных в инвертированной таблице Инвертированные таблицы — это когда мы храним пары ключ/значение в отдельных строках. В этом случае ключи и значения становятся столбцами, что обеспечивает гибкость. Преимущества такого подхода: - Мы можем хранить «бесконечное» количество пользовательских данных. - Мы можем отфильтровать отдельные строки, чтобы получить одно значение. - Мы можем реализовать логику уникальности ключей для каждой сущности. Недостатки: - Столбцы значений должны иметь строгий тип, скорее всего строковый тип. - Эти таблицы могут быстро расти в зависимости от объема пользовательских данных. Настройка Настройка инвертированной таблицы не отличается от типичных отношений «один ко многим».
public class Entity
{
  public int Id { get; set; }
  public DateTime CreatedAt { get; set; }
    = DateTime.UtcNow;
  public ICollection<Values> Values { get; set; }
    = new List<Values>();

  public Entity AddValue(string name, string value)
  {
    var existing = Values?.
      FirstOrDefault(v => v.Name.Equals(name));

    if (existing is { })
      existing.Value = value;
    else
      Values?.Add(
       new Values {Name = name, Value = value}
      );

    return this;
  }
}

public class Values
{
  public int Id { get; set; }
  public int EntityId { get; set; }
  public string Name { get; set; }
  public string Value { get; set; }
}

Метод AddValue в типе Entity будет работать с оговоркой, что у вас есть все значения из связанной таблицы Values в памяти. Если нет, вы получите повторяющиеся пары ключ/значение в своей коллекции. Посмотрим, как сохранить эти пользовательские значения:
var invertedTable = new Entity()
  .AddValue("Name", "Dotnet")
  .AddValue("Status", "Awesome");

Разница с первым методом в том, что подход с инвертированной таблицей требует включения значений при чтении сущностей из базы данных:
var invertedTable = db
  .EntityWithInvertedTables
  .OrderByDescending(o => o.CreatedAt)
  .Include(x => x.Values)
  .First();

Вызов Include загрузит все значения из связанной таблицы. Хотя, вы можете загрузить только нужные значения (но помните, что в этом случае метод сущности AddValue перестанет корректно работать):
…
  .Include(x => x.Values.Where(v => v.Name == "Name"))
  .First();

Источник: https://khalidabuhakmeh.com/storing-dynamic-user-data-with-ef-core