Imagine these three EF classes
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; }
}
Imagine now that we need multiple actions, all similar with each other, that return JSON.
lets call this Approach (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);
}
The problem with it is that the ToList() is required for the methods AsJson() to be used... so there's a considerable amount of work done in memory
In the following approach, lets call it Approach (B), this is not a problem.. the work done in memory is the minimum, and most of the work is done in SQL. In fact, it is one large SQL query that contains everything needed..
// 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);
}
Approach A.
Pros: Neat code, I can reuse code in other actions, less coupling
Cons: performance issues (work done in memory!)
Approach B:
Pros: Uggly code, if other action needs something similar, I'll end up copy pasting code! which brings coupling (modify similar code multiple times)
Cons: No performance issues (work done in SQL!)
Finally, the question: Im looking for another approach (C), that has the better of both (A) and (B), Reutilization and no performance issues
I'd like to hear how big systems, with many navigation properties, achieve this.
How they manage to reduce coupling when different JSONS (that share subparts) are required
Also, a sub-question:
In approach (A), will the following make a difference?
db.MusicBands.Include(g => g.Members.Select(m => m.Instrument)).SingleOrDefault(g => g.MusicBandId == musicBandId)
or it wont? (keeping the rest of the code with no change)