5
votes
\$\begingroup\$

Simple question:

What would you rather do?

public class FooRepository
{
    public Foo GetById(int id)
    {
        Foo foo = null;
        using (IDataReader data = /* Get Foo's data */)
        {
            // Let the Foo object set it's own fields using the data object
            foo = new Foo(data);
        }
        return foo;
    }
}

Or...

public class FooRepository
{
    public Foo GetById(int id)
    {
        Foo foo = null;
        using (IDataReader data = /* Get Foo's data */)
        {
            // Let the Repository class set the Foo object fields
            foo = new Foo();
            foo.Id = Convert.ToInt32(data["FooID"]);
            foo.Name = data["Name"].ToString();
        }
        return foo;
    }
}

Assuming you can't use an ORM (NHibernate, L2S, EF) to handle this for you and that you will need to create Foo in other methods of the repository.

Any explanation will be welcome!

\$\endgroup\$
3
votes
\$\begingroup\$

Part of the goal for using the Repository pattern is to separate the storage from the domain. By passing the IDataReader in to a Foo object, I feel like the domain gains too much knowledge of the underlying storage mechanism.

So, between the options listed, I prefer setting the object's properties in the Repository. That being said, if the object doesn't make sense without a certain property, it should still demand it during its creation. However, even in this case, the Repository would still be responsible for setting all the properties requested.

\$\endgroup\$
  • \$\begingroup\$ Thanks! I have found the first case to be useful in certain cases (by using inheritance and constructor inheritance for example), but still think that the second one separates concerns more clearly. \$\endgroup\$ – Meryovi Sep 29 '11 at 22:20
2
votes
\$\begingroup\$

I would vote for the second option for sure, because it allows you to separate your domain objects from the database. Mapping is a responsibility of a data access layer and not of domain objects. But usually these kind of logic is moved to a special classes which are called DataMappers.

\$\endgroup\$
  • \$\begingroup\$ Great, thanks! Regarding DataMappers, wouldn't that be an overkill if I were always using Databases? I've been using the first approach because it's easier, but I'm considering to start using the second one to clearly separate concerns. \$\endgroup\$ – Meryovi Sep 29 '11 at 22:04
2
votes
\$\begingroup\$

Given no ORM, I generally have a DAL helper method like:

IEnumerable<T> ExecuteEnumerable<T>(string commandText, CommandType commandType, IEnumerable<IDbDataParameter> parameters, Func<IDataRecord, T> processRecord)
{
    ...
    using(IDataReader reader ...)
    {
        while(reader.Read())
        {
            yield return reader;
        }
    }
}

Then I'd use it as follows:

private static Foo GetFooFromRecord(IDataRecord record)
{
    foo = new Foo();                     
    foo.Id = Convert.ToInt32(record["FooID"]);                     
    foo.Name = record["Name"].ToString();
    return foo;
}

public Foo GetById(int id)            
{   
    ... 
    // PK - I know there's at most one result
    return ExecuteEnumerable(..., GetFooFromRecord).FirstOrDefault(); 
}

public IList<Foo> GetByName(string name)
{
    ... 
    // May be more than one match
    return ExecuteEnumerable(..., GetFooFromRecord).ToList(); 
}

The static GetFooFromRecord method is in the repository, and can be reused for multiple queries.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.