2016-05-16 19 views
15

'u çağırma EF Code First uygulamasını kullanarak, birbirlerinin koleksiyonlarını içeren sınıfları oluşturdum. varlık sayısı:AutoMapper, ProjectTo <T>() için çağrı yaparken StackOverflowException öğesini atıyor IQueryable

public class Field 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual List<AppUser> Teachers { get; set; } 
    public Field() 
    { 
     Teachers = new List<AppUser>(); 
    } 
} 

public class AppUser 
{ 
    public int Id { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
    public string UserName => Email; 
    public virtual List<Field> Fields { get; set; } 
    public AppUser() 
    { 
     Fields = new List<FieldDTO>(); 
    } 
} 

DTOs:

public class FieldDTO 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public List<AppUserDTO> Teachers { get; set; } 
    public FieldDTO() 
    { 
     Teachers = new List<AppUserDTO>(); 
    } 
} 

public class AppUserDTO 
{ 
    public int Id { get; set; } 
    public string Email { get; set; } 
    public string Password { get; set; } 
    public string UserName => Email; 
    public List<FieldDTO> Fields { get; set; } 
    public AppUserDTO() 
    { 
     Fields = new List<FieldDTO>(); 
    } 
} 

Eşlemeler:

Mapper.CreateMap<Field, FieldDTO>(); 
Mapper.CreateMap<FieldDTO, Field>(); 
Mapper.CreateMap<AppUserDTO, AppUser>(); 
Mapper.CreateMap<AppUser, AppUserDTO>(); 

Ve bu kodu çağrılırken ben StackOverflowException alıyorum (Bağlam benim DBContext ise):

protected override IQueryable<FieldDTO> GetQueryable() 
{ 
    IQueryable<Field> query = Context.Fields; 
    return query.ProjectTo<FieldDTO>();//exception thrown here 
} 

Sanırım bu, Listeler'de birbirini sonsuza dek aradığı için döngüye girer. Ama bunun neden olduğunu anlamıyorum. Haritalarım yanlış mı? Özdeğerleme varlıklarınız VE kendi kendini referans veren DTO'larınız var.

+0

Haklısınız:

CreateMap<AppUser, AppUserDTO>().PreserveReferences(); 
erikscandola

cevap

23

Genel anlamda kendi kendini referans alan DTO'lar kötü bir fikirdir. Özellikle bir projeksiyon yaparken - EF birlikte nasıl bir araya geleceğini ve bir araya nasıl katılacağını ve bir öğe hiyerarşisini nasıl birleştireceğini bilmez.

İki seçeneğiniz var.

İlk olarak, açıkça akılda bir hiyerarşi ile DTOs modelleyerek hiyerarşinin belirli bir derinliğe zorlayabilirsiniz: o en belirgin ve açık olduğu gibi

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>(); 
    } 
} 

Bu, tercih edilen bir yoldur.

az belirgin, daha az açık yolu hiyerarşik ilişkileri çapraz gidecek maksimum derinliğe sahip AutoMapper yapılandırmaktır: Ben çünkü en kolay anlaşılır 1. gitmeyi tercih

CreateMap<AppUser, AppUserDTO>().MaxDepth(3); 

ama # 2 de çalışır.

+0

Teşekkür ederim Jimmy. Bana gerçekten yardım ettin. Bence ilk tercihim için gideceğim. Bütün kodu yeniden kodlamak biraz zaman alacak ama buna değecek. – Peter

+0

@Jimmy Bogard: İlk yaklaşımda, haritalama sırası önemli mi? –

+0

.MaxDepth (n) 'nin, test sırasında haritanın tamamlanmasını sağlamak için çok faydalı olduğunu görüyorum, böylece karmaşık grafikler için özyinenin nereden geldiğini bulmak için kazıyorum. Ama sonradan her zaman çıkarırım, böylece eğer model değişirse ve özyineleme yeniden kazara yeniden verilirse, tekrar bir hata alırız. –

7

Diğer seçenek, PreserveReferences() yöntemini kullanıyor.

 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

Eğer hata yapmıyorsam, MaxDepth otomatik olarak – cdie

+0

PreserveReferences, ProjectTo için geçerli değildir. –

0

bu jenerik yöntemi kullanın. Sorun, listelerde mapper çağrıldığında sonsuz bir döngüdür. Haritaların doğru. Varlıkları dönüştürmeden önce listeleri boşaltmayı deneyebilirsiniz.
+0

Performans çok acıklı olurdu! –