Question

I have an object:

public class Folder : DBObjectBase
{
    public string Name { get; set; }
    public List<FileEntry> Files { get; set; }
    public Folder ParentFolder { get; set; }
    public List<Folder> ChildFolders { get; set; }
}

and I've written a query that retrieves a folder structure and all files within each folder:

var results = DbContext.Set<Folder>()
            .Include(f => f.ParentFolder)
            .Include(f => f.ChildFolders)
            .Include(f => f.Files)
            .Include(f => f.ChildFolders.Select(f1 => f1.Files))
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.Files))
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.ChildFolders.Select(f3 => f3.Files)))
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.ChildFolders.Select(f3 => f3.ChildFolders.Select(f4 => f4.Files))))
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.ChildFolders.Select(f3 => f3.ChildFolders.Select(f4 => f4.ChildFolders.Select(f5 => f5.Files)))))
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.ChildFolders.Select(f3 => f3.ChildFolders.Select(f4 => f4.ChildFolders.Select(f5 => f5.ChildFolders.Select(f6 => f6.Files))))))
            .Where(f => f.ParentFolder == null);

The above returns exactly what I need, but I don't like the code, cause it causes problems if I would like to add multiple more layers to the folder structure.

Any ideas how I could write this, so I get all Child folders, and all files despite the number of layers I have in my folder structure?

Was it helpful?

Solution

Sadly there is no recursive support in LINQ AFAIK (I faced the same problem), but you at least can shorten it to:

var results = DbContext.Set<Folder>()
            .Include(f => f.ParentFolder)
            .Include(f => f.Files)
            .Include(f => f.ChildFolders.Select(f1 => f1.ChildFolders).Select(f2 => f.ChildFolders.Select(f3 => f3.ChildFolders.Select(f4 => f4.ChildFolders.Select(f5 => f5.ChildFolders.Select(f6 => f6.Files))))))
            .Where(f.ParentFolder == null);

All "lower levels" are also included if you select the "higher level".

I THINK this is because SQL also has no support for this...

If you are fine with executing this "in code" using multiple queries to the DB (or you not using a DB at all) see golergka's comment.

OTHER TIPS

You have a tree of folders, and you'd like to look for all files recursively. This can be done using algorithms like depth-first search:

public static IEnumerable<FileEntry> GetAllFiles(Folder folder)
{
    foreach(var file in folder.Files)
    {
        yield return file;
    }
    foreach(var nestedFolder in folder.ChildFolders)
    {
        foreach(var file in GetAllFiles(nestedFolder))
        {
            yield return file;
        }
    }
}

This isn't very pretty in C# since it has no support for yielding multiple results, but it works. Also, if you have huge quantities of files, or very nested folders, you might want to implement this algorithm using more efficient techniques (e.g. with a Queue).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top