c# - 避免 Linq-To-Objects 但允许重用代码

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

想象一下这三个 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);
    }

问题是要使用 AsJson() 方法需要 ToList()...所以需要做大量的工作内存


在下面的方法中,我们称之为方法(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)

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

最佳答案

您的问题的起点是实体类中的这些 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(或 View 模型)对象。这时像 AutoMapper 这样的工具就派上用场了。

关于c# - 避免 Linq-To-Objects 但允许重用代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23284680/

相关文章:

c# - 将 LINQ 查询作为字符串发送到 Entity Framework

c# - 将单个 LINQ 值转换为字符串

c# - 从 XML 获取内在值(value)

c# - ASP.NET 无法使文件夹不可访问

c# - 另一个无法加载文件或程序集'EntityFramework

c# - LINQ to Entities 无法识别 Replace 方法?

c# - MySql 上的 EF Core `update-database` 失败, `__EFMigrationsHistory' 不存在`

c# - 找不到段 'x' 的资源

c# - XAML 数据绑定(bind) - UI 不会自动更新

c# - LINQ to Entities 中的 Enum.HasFlag?