I am having issues finding a good way to convert Entities with their children to DTO objects. For this post I've created pseudo code which is a simplified example that leaves out the database context, DTO objects. Assuming I have a parent Entity and child Entity:
public class Parent {
int Id;
string Name;
List<Child> Children;
}
public class Child {
int Id;
string Name;
Parent Parent;
int ParentId;
}
I've looked at two possibilities, but I haven't been able to find a good solution. Please have a look at the two examples and where I got stuck.
1. Example using select queries
To retreive all the parent entities as DTO's, I could then in a Controller do:
public IHttpActionResult GetParents()
{
var children = from c in _context.Children
select new ChildDTO()
{
Id = c.Id,
Name= c.Name
};
var parents = from p in _context.Parents
select new ParentDTO()
{
Id = p.Id,
Name = p.Name
Children = children.ToList(),
};
return parents;
}
This will return the parent DTO object with all its children as DTO objects. If I wanted to create a new function to get just Parent with id '1', I would at the moment have to duplicate the select statement to add a where clause:
public IHttpActionResult GetParent(int parentId)
{
var parents = from p in _context.Parents where p.id == parentId
...
And there might also be cases where I do not want the child objects back if I just want to display a list of parents. Which would mean that I would basically have to duplicate the code and change the select to this:
select new ParentDTO()
{
Id = p.Id,
Name = p.Name
//Removed the Children
//Children = children.ToList(),
};
In this example I do not see a good way to reuse code as much as possible, so that I don't end up writing the same basic select statements over and over.
2. Example using Expressions
I could also create Expressions for the parent and child, but I would not know
private static readonly Expression<Func<Child, ChildDTO>> AsChildDTO =
p => new ChildDTO()
{
Id = p.Id,
Name = p.Name
};
private static readonly Expression<Func<Parent, ParentDTO>> AsParentDTO =
p => new ParentDTO()
{
Id = p.Id,
Name = p.Name
};
To get the parents I could then in my controller do:
...
//Get list of parents
var parents = _context.Parents.Select(AsParentDTO);
//Or: Get only parent with Id
var specificParent= _context.Parents
.Select(AsParentDTO)
.Where(p => p.Id == 1);
return parents;
...
This solution seems good to me since I can reuse the Epressions and extend them if I want. I only do not seem to be able to Include the children to the parent this way:
...
var parents = _context.Parents
.Include(p => p.Children)
//I have no idea if it is possible to Invoke the child Expression here...
.Select(p => p.Children= AsChildDTO.Invoke()) //<-- this does not work
.Select(AsParentDTO)
...
As I wrote in the comment above; I have no idea if it is possible to somehow invoke the Child Expression here.
Outro
These are the two things I tried but got stuck with. But it could also be that I am missing a very obvious solution. My Question is how do I solve this issue in a way that I can reuse as much code as possible?