#c# #entity-framework-core #entity-framework-core-2.1 #entity-framework-core-2.2
#c# #entity-framework-core #entity-framework-core-2.1 #entity-framework-core-2.2
Вопрос:
Имея таблицу, ссылающуюся на себя, с атрибутом ParentID, который содержит идентификатор родительской записи, что я могу сделать, чтобы с помощью ef я загружал в каждого родителя его дочерние элементы.
Я хочу преобразовать этот cte, который вернет полную иерархию в виде коллекции.
var queryString = @"
;WITH cte AS (
SELECT * FROM [dbo].[Folders] _f WHERE _f.[Id] = @id
UNION ALL
SELECT _c.* FROM [dbo].[Folders] _c
INNER JOIN cte _cte
ON _cte.[Id] = _c.[ParentFolderId]
)
SELECT * FROM cte";
return await this.Entities.FromSql(new RawSqlString(queryString), new SqlParameter("id", id)).ToListAsync();
во что-то, что каким-то образом загрузит иерархию дочерних элементов в их родителей, сохраняя при этом производительность одного перехода к БД.
class Folder
{
public int Id { get; set; }
public int? FolderId { get; set; }
public Folder Folder { get; set; }
public IEnumerable<Folder> Children { get; set; }
}
Пример иерархии
- Main (Id: 1 / ParentId: null)
- C1 (2/1)
- C11 (4/2)
- C111 (7/4)
- C12 (5/2)
- C2 (3/1)
- C21 (6/3)
- C211 (8/6)
Настроенное отношение
builder.Ignore(prop => prop.Folder);
builder.HasOne(prop => prop.Folder).WithMany(prop => prop.Children).HasForeignKey(fk => fk.FolderId);
Комментарии:
1. EF не может сгенерировать этот CTE. Если вы используете его, например, с
FromSqlRaw
илиFromSqlInterpolated
, ядро EF может использовать идентификаторы для восстановления иерархии, если объекты DbContext настроены правильно (отношения и т. Д.)2. Другой вариант — использовать
hierarchyid
вместо самоссылки и EFCore.SQLServer. Пакет HierarchyId . Выполнение запросов, безусловно, будет проще и быстрее. Даже если в какой-то момент вы решите удалить этот пакет, будет намного проще писать иерархические SQL-запросы сhierarchyid
3. Я не вижу, чтобы FromSqlRaw или FromSqlInterpolated были доступны для версии 2.x EF core. Посмотрю в библиотеку HierarchyId, спасибо.
4. В версии 2.0 это
FromSql
для обоих, и вы должны быть очень осторожны, если используете интерполированные строки, иначе вы можете получить хорошую SQL-инъекцию. Вот почему в EF Core 3 есть два отдельных метода для интерполированных или параметризованных запросов
Ответ №1:
Если вам нужна вся иерархия в одном запросе, это просто. Просто извлеките все папки, и если отслеживание изменений включено, EF исправит все отношения. Т.Е. если вы просто запустите
var folders = db.Set<Folder>().ToList();
У вас будет целая иерархия со всеми заполненными свойствами навигации.
Комментарии:
1. Не совсем уверен, что вы подразумеваете под извлечением всех папок? Я предполагаю, что вы относитесь к папкам в просматриваемой папке?
Ответ №2:
Вы можете получить всю иерархию с помощью этого запроса:
var hierarchy = db.Set<Folder>().Include(f => f.Children).ToList();