Depending on the scope of my application, I like to put the object hydration mechanisms in the object itself. I'll wrap the data reader with a custom object and pass it a delegate that gets executed once the query returns. The delegate gets passed the DataReader. Then, since I'm in my smart business object, I can hydrate away with my private setters.
The "DataAccessWrapper" wraps all of the connection and object lifecycle management for me. So, when I call "ExecuteDataReader," it creates the connection, with the passed proc (there's an overload for params,) executes it, executes the delegate and then cleans up after itself.
public class User
{
public static List<User> GetAllUsers()
{
DataAccessWrapper daw = new DataAccessWrapper();
return (List<User>)(daw.ExecuteDataReader("MyProc", new ReaderDelegate(ReadList)));
}
protected static object ReadList(SQLDataReader dr)
{
List<User> retVal = new List<User>();
while(dr.Read())
{
User temp = new User();
temp.Prop1 = dr.GetString("Prop1");
temp.Prop2 = dr.GetInt("Prop2");
retVal.Add(temp);
}
return retVal;
}
}