I have created classes using EF Code First that have collections of each other. Entities:
public class Field
{
public int Id { get; set; }
public str
I use this generic method:
public static TTarget Convert<TSource, TTarget>(TSource sourceItem)
{
if (null == sourceItem)
{
return default(TTarget);
}
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace, ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var serializedObject = JsonConvert.SerializeObject(sourceItem, deserializeSettings);
return JsonConvert.DeserializeObject<TTarget>(serializedObject);
}
You have self-referencing entities AND self-referencing DTOs. Generally speaking self-referencing DTOs are a bad idea. Especially when doing a projection - EF does not know how to join together and join together and join together a hierarchy of items.
You have two choices.
First, you can force a specific depth of hierarchy by explicitly modeling your DTOs with a hierarchy in mind:
public class FieldDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<TeacherDTO> Teachers { get; set; }
public FieldDTO()
{
Teachers = new List<TeacherDTO>();
}
}
public class TeacherDTO
{
public int Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string UserName => Email;
}
public class AppUserDTO : TeacherDTO
{
public List<FieldDTO> Fields { get; set; }
public AppUserDTO()
{
Fields = new List<FieldDTO>();
}
}
This is the preferred way, as it's the most obvious and explicit.
The less obvious, less explicit way is to configure AutoMapper to have a maximum depth it will go to traverse hierarchical relationships:
CreateMap<AppUser, AppUserDTO>().MaxDepth(3);
I prefer to go #1 because it's the most easily understood, but #2 works as well.
...
MapperConfiguration(cfg =>
{
cfg.ForAllMaps((map, exp) => exp.MaxDepth(1));
...
Other option is using PreserveReferences() method.
CreateMap<AppUser, AppUserDTO>().PreserveReferences();