在IQueryable调用ProjectTo< T>()时,AutoMapper会抛出StackOverflowException [英] AutoMapper throwing StackOverflowException when calling ProjectTo<T>() on IQueryable

查看:160
本文介绍了在IQueryable调用ProjectTo< T>()时,AutoMapper会抛出StackOverflowException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经使用EF Code First创建了彼此集合的类。
实体:

  public class Field 
{
public int Id {get;组; }
public string Name {get;组; }
public virtual List< AppUser>老师{get;组; }
public Field()
{
教师=新List< AppUser>();
}
}

public class AppUser
{
public int Id {get;组; }
public string Email {get;组; }
public string Password {get;组; }
public string UserName =>电子邮件;
public virtual List< Field>字段{get;组; }
public AppUser()
{
Fields = new List< FieldDTO>();
}
}

DTO:

  public class FieldDTO 
{
public int Id {get;组; }
public string Name {get;组; }
public List< AppUserDTO>老师{get;组; }
public FieldDTO()
{
教师=新列表< AppUserDTO>();
}
}

public class AppUserDTO
{
public int Id {get;组; }
public string Email {get;组; }
public string Password {get;组; }
public string UserName =>电子邮件;
public List< FieldDTO>字段{get;组; }
public AppUserDTO()
{
Fields = new List< FieldDTO>();
}
}

Mappings:

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

当调用此代码(Context is my dbContext)时,我正在获取StackOverflowException:

  protected override IQueryable< FieldDTO> GetQueryable()
{
IQueryable< Field> query = Context.Fields;
return query.ProjectTo< FieldDTO>(); //这里抛出的异常
}

我想这是因为它循环在列表中无休止地相互呼唤。但我不明白为什么会发生这种情况。我的映射错误吗?

解决方案

您有自引用实体和自引用的DTO。一般来说,自我参考的DTO是一个坏主意。特别是在进行投影时 - EF不知道如何联合在一起并结合在一起,将项目层次结合在一起。



你有两个选择。



首先,您可以通过以层次结构明确建模您的DTO来强制具体的层次结构:

  public class FieldDTO 
{
public int Id {get;组; }
public string Name {get;组; }
public List< TeacherDTO>老师{get;组; }
public FieldDTO()
{
教师=新List< TeacherDTO>();
}
}

public class TeacherDTO
{
public int Id {get;组; }
public string Email {get;组; }
public string Password {get;组; }
public string UserName =>电子邮件;
}

public class AppUserDTO:TeacherDTO
{
public List< FieldDTO>字段{get;组; }
public AppUserDTO()
{
Fields = new List< FieldDTO>();
}
}

这是首选方式,因为它是最明显的并且显式地。



不那么明显的,不明确的方法是配置AutoMapper具有将遍历层次关系的最大深度:

  CreateMap&AppUser,AppUserDTO>()。MaxDepth(3); 

我喜欢去#1,因为它是最容易理解的,但是#2也是这样。 / p>

I have created classes using EF Code First that have collections of each other. Entities:

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

Mappings:

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

And I am getting StackOverflowException when calling this code (Context is my dbContext):

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

I guess this happens because it loops in Lists calling each other endlessly. But I do not understand why this happens. Are my mappings wrong?

解决方案

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.

这篇关于在IQueryable调用ProjectTo&lt; T&gt;()时,AutoMapper会抛出StackOverflowException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆