День 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