Question

For reasons beyond my control I cannot use a real ORM, so I am forced to create a custom DAL that sits over the raw data and returns "domain objects" to the consumer. Also for reasons beyond my control I must use Stored Procedures for data access.

I am making use of the Factory and Repository patterns for data access, or at least in basic theory:

  1. The call to SqlCommand and friends is hidden by a Repository class that takes parameters as needed and returns domain objects.
  2. To create the domain object, the Repository has an internal reference to a Factory of it's own type (e.g. Customer, Order, etc.). The factory has a single method, Create, which takes a DataRow as its input and maps the DataRow's columns to properties of the domain object.

This seems to work fairly well for basic objects that map to a single table. Now, here's the issue I'm running into: I want some of these domain objects to be richer and have collections of related objects. Here's a concrete example of a domain object in this system I'm working on:

class Case
{
    public string CaseNumber { get; internal set; }
    public ICollection<Message> Messages { get; set; }
}

class Message
{
    public int MessageId { get; internal set; }
    public string Content { get; set; }
}

In simple parlance, Case has many Messages. My concern is the best way to retrieve the raw data for a Case, since I also need a list of associated messages. It seems to me I can either:

  1. Run a second stored procedure in the CaseRepository when I retrieve a Case to get all the Messages that belong to it - this doesn't seem like a good idea because it means every time I look up a Case, I'm making two database calls instead of one.
  2. Use one stored procedure that returns two tables (One containing a single row with information for the Case, one containing zero or more rows with messages that belong to it) and calling two factory methods i.e. CaseFactory.Create(caseDataRow) and a loop that calls MessageFactory.Create(messageDataRow). This makes more sense as the Case is the aggregate root (or pretending to be one as the case may be) so should know how to create messages that hang off of it.

The second option seems better performance but more code. Is there a third option I'm overlooking or is #2 the best way to handle this kind of composite object when I can't use a true ORM (or even something like Linq to SQL)

Was it helpful?

Solution

As it stands, your repositories are more like table gateways (even via sprocs). You'll need a new layer of repositories, which have access to one or more table gateways, and are able to assemble the composite domain entities from the data returned from many tables.

class Customer
{
    string name; // etc
    Address homeAddress;
    Order[] orders;
}

interface ICustomerTableGateway { ... }

interface IAddressTableGateway { ... }

interface IOrderTableGateway { ... }

class CustomerRepository
{
    Customer Get(int id)
    {
        customer = customerTableGateway.Get(id);
        customer.Address = addressTableGateway.Get(customer.id);
        customer.Orders = orderTableGateway.GetAll(customer.id);
    }
}

If you can return multiple tables from the single sproc than that simplifies things further :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top