Implementing recursive property loading in EF Core
I do not have a database so I just did it in memory but if you follow my comments, it will work for you. Notice the objects I have in memory, only comment with id 2 has replies.
LoadComment
method is where everything happens. The rest is just setup code I needed.
class Program
{
static void Main(string[] args)
{
var result = LoadComment(1, null);
Console.ReadKey();
}
public static Comment LoadComment(long id, Comment com)
{
Comment res = new Comment();
if( com == null )
{
// You would call your context here and write db.Single(x => x.Id == id).Include(x => x.User.Avatar);
var first = db.Single( x => x.Id == id );
res = new Comment { Id = first.Id, Replies = first.Replies.ToList(), User = first.User };
foreach( var item in first.Replies )
{
LoadComment( item.Id, item );
}
}
else
{
// You would call your context here and write db.Single(x => x.Id == id).Include(x => x.User.Avatar);
var child = db.SingleOrDefault( x => x.Id == id );
if( child == null )
{
return null;
}
com.Replies = new List<Comment>();
com.Replies.Add( new Comment { Id = child.Id, Replies = child.Replies.ToList(), User = child.User } );
foreach( var item in child.Replies )
{
LoadComment( item.Id, com );
}
}
return res;
}
private static Comment cm1 = new Comment
{
Id = 1,
User = new User { Id = 1, Avatar = new Avatar { Url = "1" } },
Replies = new List<Comment> {
new Comment { Id = 2 },
new Comment { Id = 3 },
new Comment { Id = 4 },
new Comment { Id = 5 } },
Content = "ContentForCommentId1"
};
private static Comment cm2 = new Comment
{
Id = 2,
User = new User { Id = 2, Avatar = new Avatar { Url = "2" } },
Replies = new List<Comment> {
new Comment { Id = 22 },
new Comment { Id = 33 },
new Comment { Id = 44 },
new Comment { Id = 55 } },
Content = "ContentForCommentId2"
};
private static List<Comment> db = new List<Comment> { cm1, cm2 };
}
This is how I solved it. Fairly similar to Yoshi's but could be helpful to someone.
private async Task<Comment> GetComment(Guid id, CancellationToken cancellationToken)
{
var wm = await _context.Comments
.Include(x => x.Replies)
.SingleOrDefaultAsync(x => x.Id == id, cancellationToken);
for (var i = 0; i < wm.Replies.Count; i++)
{
if (!wm.Replies[i].IsDeleted)
wm.Replies[i] = await GetComment(wm.Replies[i].Id, cancellationToken);
}
return wm;
}