【问题标题】:Avoiding Linq-To-Objects but allowing reutilization of code避免 Linq-To-Objects 但允许重用代码
【发布时间】:2014-04-25 05:16:52
【问题描述】:

想象一下这三个 EF 类

    class Instrument
    {
        public long InstrumentId { get; set; }
        public string Model { get; set; }

        public dynamic AsJson()
        {
            return new  
            {
               instrumentId = this.InstrumentId,
               model = this.Model
            }
        }
    }

    class Musician
    {
        public long MusicianId { get; set; }
        public virtual Instrument Instrument { get; set; }  // notice navigation
        public string Name { get; set; } 

        public dynamic AsJson()
        {
            return new  
            {
               musicianId = this.MusicianId,
               name = this.Name,
               instrument = this.Instrument.AsJson()
            }
        }
    }

    class MusicBand
    {
        public long MusicBandId { get; set; }
        public string Name { get; set; } 
        public virtual List<Musician> Members { get; set; }
    }



现在想象一下,我们需要返回 JSON 的多个彼此相似的操作。
让我们称之为方法(A)

    // ajax/Bands/Members
    //
    public JsonResult Members(long musicBandId)
    {
        MusicBand g = db.MusicBands.SingleOrDefault(g => g.MusicBandId == musicBandId);

        if (g == null)
             return null;

        return Json(new
        {
            error = false,
            message = "",
            members = from p in g.Members.ToList() select p.AsJson()

        }, JsonRequestBehavior.AllowGet);
    }

它的问题是 ToList() 是使用方法 AsJson() 所必需的......所以在内存中完成了大量工作


在下面的方法中,我们称之为方法(B),这不是问题。在内存中完成的工作是最少的,大部分工作都是在SQL中完成的。事实上,它是一个包含所有需要的大型 SQL 查询。

    // ajax/Bands/Members
    //
    public JsonResult Members(long musicBandId)
    {
        MusicBand g = db.MusicBands.SingleOrDefault(g => g.MusicBandId == musicBandId);

        if (g == null)
             return null;

        return Json(new
        {
            error = false,
            message = "",
            persons = from p in g.Members select new
                      {
                          musicianId = p.MusicianId,
                          name = p.Name,
                          instrument = select new 
                                       {
                                          instrumentId = instrument.InstrumentId,
                                          model = instrument.Model
                                       }
                      }

        }, JsonRequestBehavior.AllowGet);
    }




方法 A.
优点:整洁的代码,我可以在其他操作中重用代码,减少耦合
缺点:性能问题(在内存中完成的工作!)

方法 B:
优点:丑陋的代码,如果其他操作需要类似的东西,我最终会复制粘贴代码!这带来了耦合(多次修改类似的代码)
缺点:没有性能问题(使用 SQL 完成工作!)

最后,问题: 我正在寻找另一种方法(C),它具有更好的(A)和(B), 重复利用且无性能问题

我想知道具有许多导航属性的大型系统是如何实现这一目标的。
当需要不同的 JSONS(共享子部分)时,他们如何设法减少耦合

还有一个子问题:
在方法 (A) 中,以下内容会有所不同吗?

db.MusicBands.Include(g => g.Members.Select(m => m.Instrument)).SingleOrDefault(g => g.MusicBandId == musicBandId)

还是不会? (保持其余代码不变)

【问题讨论】:

    标签: c# entity-framework linq-to-entities linq-to-objects code-reuse


    【解决方案1】:

    您问题的起点是实体类中的这些AsJson() 方法。但那是我一开始不会做的事情。首先,它在您的领域中引入了传输概念,其次,实体的表示可能取决于用例:也许在其他情况下,您只想展示没有乐器的音乐家。

    如果您想将实体序列化为 JSON,您通常需要禁用代理生成,这会禁用延迟加载并具体化原始实体类型...

    db.ProxyCreationEnabled = false;
    

    ...并急切地加载您想要返回的所有内容...

    MusicBand g = db.MusicBands
                    .Include(mb => mb.Members.Select(m => m.Instrument))
                    .SingleOrDefault(mb => mb.MusicBandId == musicBandId);
    

    ...并以 JSON 格式返回 g

    这在一个 SQL 查询中完成。在您的替代方案中,总会有至少两个查询,因为您首先获取 MusicBand,然后通过延迟加载获取成员(和工具)。

    如果您想序列化实体的其他表示,则应将其映射到 DTO(或视图模型)对象。在这里,像 AutoMapper 这样的工具就派上用场了。

    【讨论】:

    • 您更多地关注我遇到的性能问题,这是我正在寻找的 50%。另外 50% 是再利用,这就是我遇到的问题。如果我需要在每个不同的查询中填写这些 DTO,这些 DTO 将如何帮助我实现这一目标?
    • 使用 AutoMapper,这可能是一个简单的语句,例如 Mapper.Map&lt;MusicBandDto&gt;(g)。您可以在单个查询上添加它,但当然您也可以拥有一个公开查询并映射到不同 DTO 的服务,例如在控制器中。
    • AutoMapper 还可以在一个简短的语句中将IQueryable 直接投影到 DTO 对象列表中。
    • 如果 (AutoMapper) 解决了问题的另一半,我会看看 AutoMapper 并将您的答案标记为正确的答案
    • 如果 DTO 中的集合名称具有相同的名称,AM 还将映射嵌套集合(或者您可以配置源集合和目标集合)。它确实是摆脱所有这些嵌套的select new {} 语句的 工具。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    相关资源
    最近更新 更多