TGViewer
.NET Разработчик .NET Разработчик @netdeveloperdiary · 6.76K subscribers
Post #1599 1.28K
День 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
  • 👍 3
More from @netdeveloperdiary
  1. Oct 14, 2026Post #3373
  2. Oct 13, 2026День 2813. #ЗаметкиНаПолях #Async Ещё Раз Про Async/Await в C#. Часть 1 1. Почему существу…
  3. Oct 12, 2026День 2812. #Карьера #AI Как Разработчикам Оставаться Полезными, Когда Код Пишет ИИ? По мер…
  4. Oct 11, 2026День 2811. #ВопросыНаСобеседовании Марк Прайс предложил свой набор из 60 вопросов (как тех…
  5. Oct 10, 2026День 2810. #ЧтоНовенького #VSCode Более Быстрый и Лёгкий C# Dev Kit Мы, разработчики, люби…
  6. Oct 9, 2026День 2809. #Карьера 5 Навыков, Которые Помогут Быстрее Стать Сеньором. Окончание Начало 3.…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →