C# 避免Linq到对象,但允许代码的重用
想象一下这三个EF类C# 避免Linq到对象,但允许代码的重用,c#,entity-framework,linq-to-entities,linq-to-objects,code-reuse,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.Instru
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; }
}
它的问题是要使用方法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)的优点, 重复利用且无性能问题 我想听听有很多导航属性的大型系统是如何实现这一点的。
当需要不同的JSON(共享子部分)时,它们如何设法减少耦合 还有一个子问题:
在方法(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);
…并将g
作为JSON返回
这在一个SQL查询中完成任务。在您的备选方案中,总会有至少两个查询,因为您首先通过延迟加载获取MusicBand
,然后获取成员(和乐器)
如果要序列化实体的其他表示形式,则应映射到DTO(或视图模型)对象。这里有一个像AutoMapper这样的工具很方便。您更关注我的性能问题,这是我关注的50%。另外50%是再利用,这就是我被卡住的地方。如果我需要在每个不同的查询中填充这些DTO,这些DTO将如何帮助我实现这一点?使用AutoMapper,这可能是一个简单的语句,如
Mapper.Map(g)
。你可以在一个单独的查询中添加它,当然,你也可以使用一个服务来公开查询,并映射到不同的DTO,例如在控制器中。AutoMapper还可以在一个简短的语句中将IQueryable
直接投影到DTO对象列表中。我将看一看AutoMapper,并将你的答案标记为正确答案(AutoMapper)如果DTO中的集合名称具有相同的名称(或者您可以配置源集合和目标集合),则AM还将映射嵌套集合。它确实是摆脱所有这些嵌套的selectnew{}
语句的工具。
MusicBand g = db.MusicBands
.Include(mb => mb.Members.Select(m => m.Instrument))
.SingleOrDefault(mb => mb.MusicBandId == musicBandId);