重新使用查询中的投影,“选择新”之后的部分

时间:2014-04-25 22:51:25

标签: c# linq entity-framework projection

在我的ASP.NET MVC应用程序中,我有很多返回JSON的动作 在这些JSON中,重复了一些子结构。

例如

  1. ajax:" /乐队/会员"应该归还乐队的成员,这些都是音乐家
  2. ajax:" / Musicians / All"应该归还系统上的所有音乐家
  3. ajax:" / Musicians / Search"应该归还所有与之匹配的音乐家
  4. 等...

    这里我展示(1):

    public JsonResult Members(long musicBandId)
    {
        MusicBand b = db.MusicBands.SingleOrDefault(b => b.MusicBandId == musicBandId);
    
        if (b == null)
             return null;
    
        return Json(new
        {
            error = false,
            message = "",
            persons = from m in b.Members select new
                      {
                          musicianId = p.MusicianId,
                          name = m.Name,
                          instrument = new 
                                       {
                                          instrumentId = m.instrument.InstrumentId,
                                          model = m.instrument.Model
                                       }
                      }
    
        }, JsonRequestBehavior.AllowGet);
    }
    

    在这里我展示(2):

    public JsonResult All(int page, int pageSize)
    {
        var musicians = db.Musicians;
        var pageOfMusicians = musicians.Skip((page-1) * pageSize).Take(pageSize);
    
        return Json(new
        {
            error = false,
            message = "",
            musiciansCount = musicians.Count(),
            page = page,
            pageSize = pageSize
            musicians = from m in pageOfMusicians select new
                        {
                            musicianId = m.MusicianId,
                            name = m.Name,
                            instrument = new 
                                         {
                                            instrumentId = m.instrument.InstrumentId,
                                            model = m.instrument.Model
                                         }
                        }
    
        }, JsonRequestBehavior.AllowGet);
    }
    

    这有几个问题:

    1. 如果我想更改JSON格式,我必须在每个动作中更改它!
      例如:如果我想改变" name" to" fullname",我必须在Members()和All()中更改它

    2. 很多"复制粘贴":如果我正在创建一个新的动作,结构中的某个地方返回一个音乐家,我需要复制并粘贴代表该部分的代码片段音乐家

                    {
                        musicianId = p.MusicianId,
                        name = p.Name,
                        instrument = new 
                                     {
                                        instrumentId = instrument.InstrumentId,
                                        model = instrument.Model
                                     }
                    }
      
    3. 代码太大

    4. 这个问题有什么解决方案?
      如果你提出一个框架,请告诉我以前的查询如何看待该框架

      注意我在我的示例中总是使用Linq到实体,并且由于性能问题,我希望保持这样。我知道,对于Linq-to-objects,我可以这样:

        from m in pageOfMusicians.ToList() select m.GetDTO()
      

      使用GetDTO()某些可以使用Linq-to-Objects运行的方法 但话说回来,我想坚持Linq-to-Entities

1 个答案:

答案 0 :(得分:2)

备选方案1

如果您不担心使用与常规类型C#代码混合的动态,您可以制作一个实用方法,如...

public static dynamic PrepareForMusiciansView(IQuerable<Musician> musicians)
{
    return musicians.Select(m => new
                 {
                    musicianId = m.MusicianId,
                    name = m.Name,
                    instrument = new 
                                 {
                                    instrumentId = m.instrument.InstrumentId,
                                    model = m.instrument.Model
                                 }
                 }
}

......然后......

return Json(new
{
    error = false,
    message = "",
    musiciansCount = musicians.Count(),
    page = page,
    pageSize = pageSize
    musicians = Util.PrepareForMusiciansView(pageOfMusicians)

}, JsonRequestBehavior.AllowGet);

方法名称应明确反映其在申请方面的目的。也许您希望更多地关注序列化功能并使用类似PrepareForJson的名称。此外,它应符合您的编码标准。如果没有使用别的动力,我会避免使用它。

备选方案2

使用AutoMapper(可通过NuGet获得)。

使用AutoMapper,您通常拥有MusicianInstrument的DTO类,具有您要在视图中公开的属性。如果这些属性与源类中的属性具有相同的名称,则AutoMapper将按名称约定匹配它们。

使用AutoMapper始终涉及定义映射和执行映射。应用程序启动时应定义映射一次。它看起来像......

Mapper.CreateMap<Musician, MusicianDto>();
Mapper.CreateMap<Instrument, InstrumentDto>();

执行映射有多种方法,但在使用IQueryable时,首选方法是

musicians = pageOfMusicians.Project().To<MusicianDto>()

这会将IQueryable<Musician>投射到IQueryable<MusicianDto>,包括嵌套的Instrument(如果DTO具有该名称的属性)。

这是我可以想到的两个可行的替代方案,可以将笨拙的new {}语句减少为可重用的单行语句。这取决于您的应用程序和编码风格,您更喜欢哪种替代方案。