AutoMapper throwing StackOverflowException when calling ProjectTo() on IQueryable

前端 未结 4 1860
暗喜
暗喜 2020-12-15 18:56

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         


        
相关标签:
4条回答
  • 2020-12-15 19:19

    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);
        }
    
    0 讨论(0)
  • 2020-12-15 19:27

    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.

    0 讨论(0)
  • 2020-12-15 19:28
    ...
    MapperConfiguration(cfg =>
    {
        cfg.ForAllMaps((map, exp) => exp.MaxDepth(1));
    ...
    
    0 讨论(0)
  • 2020-12-15 19:33

    Other option is using PreserveReferences() method.

    CreateMap<AppUser, AppUserDTO>().PreserveReferences();
    
    0 讨论(0)
提交回复
热议问题