Depending on your scenario, there are multiple ways to accomplish what you want.
The simplest way is to just load all entities (EF Core will do the relationship fixup for you) and then just work from the parent you actually care about:
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");
Here is another way, that works with a single model class:
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);
}
}
}
These are quick and simple solutions. For better performance, you need to issue hierarchical queries.