使用DTO

时间:2017-03-17 21:20:19

标签: entity-framework asp.net-web-api nested linq-to-entities

我需要帮助让我的WebApi控制器工作。

我有3个这样的模型。

第一张表

public class MainTable{ 
     public int MainTableID { get; set; }

     ...  Other Fields

     public ICollection<SubTable> SubTables { get; set; }
}

第二张表

public class SubTable{ 
     public int SubTableID { get; set; }

     ...  Other Fields

     public int MainTableID { get; set; }

     [ForeignKey("MainTableID ")]
     [JsonIgnore]
     public virtual MainTable MainTable{ get; set; }

     public ICollection<SubSubTable> SubSubTables { get; set; }
}

第三表

public class SubSubTable{ 
     public int SubSubTableID { get; set; }

     ...  Other Fields

     public int SubTableID { get; set; }

     [ForeignKey("SubTableID")]
     [JsonIgnore]
     public virtual SubTable SubTable{ get; set; }
}

由于此帖中未提及的其他关系,我需要展平第一个模型,所以我使用的是dto

DTO

    public class TableDTO
    {
         public int MainTableID { get; set; }

         ...  Other Fields (there is a lot of flattening happening here but I am going to skip it to keep this simple)

         public ICollection<SubTable> SubTables { get; set; }
    }

现在我把所有这些都排除在外了。对我的问题..我将这一切都链接到web api控制器。

如果我使用DTO并创建一个像这样的控制器

使用DTO的控制器

     public IQueryable<TableDTO> GetMainTable()
     {
          var mainTable = from b in db.MainTables
          .Include(b => b.SubTable.Select(e => e.SubSubTable))
                          select new TableDTO()
                          {
                              MainTableID = b.MainTableID 
                              eager mapping of all the fields,
                              SubTables = b.SubTables
                          };

          return mainTable;
     }

这适用于除SubSubTable之外的所有返回null的内容。如果我抛弃DTO并创建一个像这样的控制器

没有DTO的控制器

public IQueryable<MainTable> GetMainTable()
{
    return db.MainTables
        .Include(c => c.SubTables)
        .Include(c => c.SubTables.Select(b => b.SubSubTables));
}

这很完美,JSon会返回我需要的所有东西,除了我丢失了我急需代码的其他方面的DTO。我已经用我能想到的各种方式重写了我的代码,但没有任何作用。我很确定这可以通过DTO来完成,但我不知道它需要什么来使它工作,并且他们说“你不知道你不知道什么”所以希望有人在这里知道。

2 个答案:

答案 0 :(得分:2)

在实体框架6(及更低版本)中,当查询在投影中结束时,始终会忽略Include,因为Include路径无法应用于最终结果。换句话说,Include仅在可以定位at the very end of the LINQ statement时才有效。 (EF-core更通用)。

这对您没有帮助,因为您明确要返回DTO。实现此目的的一种方法是在将实体实现到内存后进行投影:

var mainTable = from b in db.MainTables
      .Include(b => b.SubTable.Select(e => e.SubSubTable))
      .AsEnumerable()
                      select new MessageDTO()
                      {
                          MainTableID = b.MainTableID ,
                          // eager mapping of all the fields,
                          SubTables = b.SubTables
                      };

短语“所有字段的热切映射”表明,无论如何,预测都不会缩小SELECT子句的范围,因此它不会产生太大的影响。

另一种方法是将所有SubSubTable个对象加载到您知道将从数据库中提取的MainTable中的上下文中。 EF将通过 relationship fixup 填充所有SubTable.SubSubTables个集合。

答案 1 :(得分:0)

如果有效:

public IQueryable<MainTable> GetMainTable()
{
    return db.MainTables
        .Include(c => c.SubTables)
        .Include(c => c.SubTables.Select(b => b.SubSubTables));
}

然后使用此广告,只需在Select()的末尾添加ToList()。请注意返回类型中的IEnumerable

public IEnumerable<MainTableDto> GetMainTable()
{
     return db.MainTables
        .Include(c => c.SubTables)
        .Include(c => c.SubTables.Select(b => b.SubSubTables))
        .Select(c=> new MainTableDto { SubTables=c.SubTables /* map your properties here */ })
        .ToList();
}

不确定类型(在一个地方MainTableDto,另一个地方你提到MessageDto?)。