views:

316

answers:

4

I'm making the switch to a more object-oriented approach to ASP.NET web applications in a new system I'm developing.

I have a common structure which most people will be familiar with. I have a school structure where there are multiple departments; courses belonging to a single department; and students belonging to multiple courses.

In a department view I list all courses belonging to the department and I want aggregated figures for each course such as number of enrolments, withdrawals, number male/female etc.

In an individual course view however, I'll need the actual list of students along with their details such as whether they are enrolled, passed course, gender etc.

And then the individual student view where all detail about a student is displayed including enrolments on other courses, address, etc.

Previously, I would have had a data access layer returning whatever data I needed in each case and returning it as an SQLDataReader or DataSet (working in VB.NET). Now, I'm trying to model this in an object-oriented approach I'm creating objects in the DAL and returning these to the BLL. I'm not sure how to handle this though when I need aggregated details in objects. For example, in the department view with the list of courses I'll have aggregates for each of the courses. Would I store a collection of some lightweight course objects in the department where those lightweight course objects store the aggregated values?

I guess there are different levels of abstraction needed in different scenarios and I'm not sure the best way to handle this. Should I have an object model where there's a very basic course object which stores aggregates, and a child object which would store the full detail?

Also, if there are any useful resources that may help my understanding of how to model these kind of things that'd be great.

+4  A: 

Do not overcomplicate things and do not do unneccessary work. Databases are perfect when it comes to data manipulation, so let the DB do the aggregation. On the code side of things, add one more object to your object model and you'll be just fine and dandy:

class CourseStats
    string Name { get; }
    int Enrollments { get; }
    int Withdrawals { get; }

The SQL to do the aggregation is pretty straightforward. Be sure, however, to use an ORM (think NHibernate) or a less sophisticated Result-Set Mapper (think BLToolkit): you don't really want to manually hydrate these objects.

An added benefit is that you can cache both query results (and invalidate cache as soon as something course-related changes).

Anton Gogolev
A: 

If there are few departments and each has a small number of courses, just load everything and have your objects do the math (i.e. the department iterates over the list of courses and just sums up what you need).

An alternative approach would be to run the sums against the database with some custom, native SQL. You can hide this in the DAL. The DAL would then return, for example, a virtual course (which doesn't exist in the database but which contains the sums).

A third approach is to keep these values somewhere in the department object and update them every time a course is changed/added/removed.

Aaron Digulla
+1  A: 

That's actually a pretty big issue that many people are struggling with.

As far as I've been able to identify, there are at least two schools of thought on this issue:

  • Persistent-ignorant Domain objects with an OR/M that supports lazy loading
  • Domain-Driven Design and explicitly modeled (and explicitly loaded) aggregates

Jeremy Miller has an article in MSDN Magazine that surveys some persistence patterns.

The book Domain-Driven Design has a good discussion on modeling Aggregates.

Mark Seemann
Thanks for your comments Mark, I've been reading that MSDN Magazine article which is very good. In the section labeled Lean Programming the author talks about the data access strategy and he does say there that for a reporting application he would just use SQL and datasets.I'm thinking that perhaps my application does fall into the reporting category and that perhaps this would be the best approach in this particular case.
Nick
I absolutely agree. Reporting is one of the very few cases where I would forgo layering and abstraction and just party directly on the DB :)
Mark Seemann
A: 

One thing you should investigate if you are working with .NET is LINQ to SQL. It will allow you to have a very elegant interface into your DAL. LINQ will allow you to craft aggregate queries in your BLL which saves plumbing code as well as nasty SQL snippets spread throughout your source. An example from the previous link of an aggregate SQL query expressed with LINQ:

var averageOrderTotals =
  customers.
  Select(c => new {
      c.Name,
      AverageOrderTotal = c.Orders.Average(o => o.Total)
   });

I've switched over my database layer to LINQ although in my case I don't use MS SQL Server so I have instead used the DbLinq library.

The very last thing you want to be doing is having to modify your classes to accommodate your database access layer, doing that approach will make your solution very fragile.

sipwiz