Иерархические данные

Последнее обновление: 23.11.2021

Некоторые данные представляют иерархическую структуру по типу деревьев, например, меню, где один пункт меню может иметь подменю. Или файловая система, где в каталоге могут быть другие каталоги. Рассмотрим, как в Entity Framework мы можем создать и использовать подобную иерархическую структуру.

Определим следующую сущность MenuItem:

public class MenuItem
{
    public int Id { get; set; }
    public string? Title { get; set; }
    public int? ParentId { get; set; }
    public MenuItem? Parent { get; set; }
    public List<MenuItem> Children { get; set; } = new();
}

MenuItem представляет пункт меню, который может иметь подменю. Свойство Title представляет некоторый текст пункта меню. Свойство Parent хранит ссылку на родительский пункт меню при его наличии, а ParentId - id родительского пункта меню. Причем поскольку у пунктов меню верхнего уровня не может быть родительских меню, то свойства ParentId и Parent определены как необязательные. А свойство Children представляет пункты подменю.

И определим следующий контекст данных:

using Microsoft.EntityFrameworkCore;

public class ApplicationContext : DbContext
{
    public DbSet<MenuItem> MenuItems { get; set; } = null!;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
}

В итоге при создании базы данных будет генерироваться следующая таблица:

CREATE TABLE "MenuItems" (
	"Id"	INTEGER NOT NULL,
	"Title"	TEXT,
	"ParentId"	INTEGER,
	CONSTRAINT "FK_MenuItems_MenuItems_ParentId" FOREIGN KEY("ParentId") REFERENCES "MenuItems"("Id"),
	CONSTRAINT "PK_MenuItems" PRIMARY KEY("Id" AUTOINCREMENT)
);

Использование MenuItem:

using (ApplicationContext db = new ApplicationContext())
{
	// пересоздаем бд
    db.Database.EnsureDeleted();
    db.Database.EnsureCreated();

	// добавляем начальные данные
    MenuItem file = new MenuItem { Title = "File" };
    MenuItem edit = new MenuItem { Title = "Edit" };
    MenuItem open = new MenuItem { Title = "Open", Parent = file };
    MenuItem save = new MenuItem { Title = "Save", Parent = file };

    MenuItem copy = new MenuItem { Title = "Copy", Parent = edit };
    MenuItem paste = new MenuItem { Title = "Paste", Parent = edit };

    db.MenuItems.AddRange(file, edit, open, save, copy, paste);
    db.SaveChanges();
}
using (ApplicationContext db = new ApplicationContext())
{
    // получаем все пункты меню из бд
    var menuItems = db.MenuItems.ToList();
    Console.WriteLine("All Menu:");
    foreach (MenuItem m in menuItems)
    {
        Console.WriteLine(m.Title);
    }
    Console.WriteLine();
    // получаем определенный пункт меню с подменю
    var fileMenu = db.MenuItems.FirstOrDefault(m => m.Title == "File");
    if(fileMenu != null)
    {
        Console.WriteLine(fileMenu.Title);
        foreach(var m in fileMenu.Children)
        {
            Console.WriteLine($"---{m.Title}");
        }
    }
}

Консольный вывод программы:

All Menu:
File
Edit
Open
Save
Copy
Paste

File
---Open
---Save
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850