В зависимости от вашего сценария, есть несколько способов достичь sh того, что вы хотите.
Самый простой способ - просто загрузить все сущности (EF Core выполнит исправление отношений за вас), а затем просто работать с родителем, который вам действительно нужен:
public class File
{
public int FileId {get; set;}
public string Name {get; set;}
public int ParentFolderId {get; set;}
public Folder ParentFolder {get; set;}
public string Path => ParentFolder?.Path + "/" + Name;
}
public class Folder
{
public int FolderId {get; set;}
public string Name {get; set;}
public int ParentFolderId {get; set;}
public Folder ParentFolder {get; set;}
public ICollection<Folder> SubFolders {get; set;} = new HashSet<Folder>();
public ICollection<Files> Files {get; set;} = new HashSet<File>();
public string Path => ParentFolder?.Path + "/" + Name;
}
context.Files.Load();
context.Folders.Load();
var rootFolderICareAbout = context.Folders.Local.FirstOrDefault(f => f.Path == "/My/Folder/Path");
Вот еще один способ, который работает с одним классом модели:
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace IssueConsoleTemplate
{
public class FileOrFolder
{
public int FileOrFolderId { get; set; }
public string Name { get; set; }
public bool IsFolder { get; set; }
public int? ParentId { get; set; }
public FileOrFolder Parent { get; set; }
public ICollection<FileOrFolder> Children { get; set; } = new HashSet<FileOrFolder>();
public bool HasAncestor(FileOrFolder parent) => Parent == parent || (Parent?.HasAncestor(parent) ?? false);
}
public class Context : DbContext
{
public DbSet<FileOrFolder> FileOrFolders { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseSqlServer(@"Data Source=.\MSSQL14;Integrated Security=SSPI;Initial Catalog=So62854494")
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<FileOrFolder>(
entity =>
{
entity.HasOne(f => f.Parent)
.WithMany(f => f.Children)
.HasForeignKey(f => f.ParentId);
entity.HasData(
new FileOrFolder {FileOrFolderId = 1, Name = "RootFolder", IsFolder = true, ParentId = null},
new FileOrFolder {FileOrFolderId = 2, Name = "RootFile1", IsFolder = false, ParentId = 1},
new FileOrFolder {FileOrFolderId = 3, Name = "RootFile2", IsFolder = false, ParentId = 1},
new FileOrFolder {FileOrFolderId = 4, Name = "SubFolder", IsFolder = true, ParentId = 1},
new FileOrFolder {FileOrFolderId = 5, Name = "SubFile1", IsFolder = false, ParentId = 4},
new FileOrFolder {FileOrFolderId = 6, Name = "SubFile2", IsFolder = false, ParentId = 4});
});
}
}
internal static class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
var rootFolder = context.FileOrFolders.Single(f => f.ParentId == null);
var subFilesOrFolders = context.FileOrFolders
.Include(f => f.Parent)
.AsEnumerable()
.Where(f => f.HasAncestor(rootFolder))
.ToList();
Debug.Assert(subFilesOrFolders.Count == 5);
Debug.Assert(subFilesOrFolders.First(f => f.IsFolder).Name == "SubFolder");
Debug.Assert(subFilesOrFolders.First(f => f.IsFolder).Children.Count == 2);
}
}
}
Это быстрые и простые решения. Для повышения производительности необходимо выполнять иерархические запросы.