In all projects since, I've used a Domain Model and Repository, typically with NHibernate for the ORM mapping/queries.
As I started using Rhino Mocks, I also created mock repositories for MVC and MVP unit testing. And I also have created fake repositories (returning collections of dummy objects), and LinqToSql repositories as part of the PRO ASP.NET MVC book examples [Sanderson].
The only combination I hadn't done was original ADO.NET/SqlDataReader in a repository.
In the following code sample, I add an ADO.NET repository to an Model-View-Presenter scenario (which originally had only mocked repository and view interfaces against a Presenter). To make a complete integration test:
1) I create a view interface implementation (WinForm) where the List<Project> setter property assigned its value to a simple data grid
2) I create an AdoNetProjectsRepository implementation class where List<Project> FindAllProjects() method returns a list of Projects from the database.
Integration test with Form1.cs and ADO.NET Repository
[TestFixture]
public class ProjectsPresenterIntegrationTests
{
[Test]
public void ShowProjectsEvent_Raised_RetrievesProjectsFromRepositoryAndAssignedToViewProjectsDisplay()
{
IProjectsRepository adoNetProjectsRepository = new AdoNetProjectsRepository();
var projects = adoNetProjectsRepository.FindAllProjects();
IProjectsView projectsView = new Form1();
projectsView.ProjectsDisplay.ShouldEqual(projects);
}
}
IProjectsView implementation as WinForm
public Form1()
{
InitializeComponent();
IProjectsRepository adoNetProjectsRepository = new AdoNetProjectsRepository();
var projectsPresenter = new ProjectsPresenter(adoNetProjectsRepository, this);
ShowProjects(this, EventArgs.Empty);
}
public event EventHandler ShowProjects;
public List<Project> ProjectsDisplay
{
get
{
return (List<Project>)dgrProjects.DataSource;
}
set
{
dgrProjects.DataSource = value;
}
}
Projects Presenter
public class ProjectsPresenter
{
private readonly IProjectsRepository _projectsRepository;
private readonly IProjectsView _projectsView;
public ProjectsPresenter(IProjectsRepository projectsRepository, IProjectsView projectsView)
{
_projectsRepository = projectsRepository;
_projectsView = projectsView;
_projectsView.ShowProjects += new EventHandler(ProjectsViewShowProjects);
}
private void ProjectsViewShowProjects(object sender, EventArgs e)
{
_projectsView.ProjectsDisplay = _projectsRepository.FindAllProjects();
}
}
ADO.NET Repository
public class AdoNetProjectsRepository : IProjectsRepository
{
public List<Project> FindAllProjects()
{
var projects = new List<Project>();
PopulateProjectsWithSqlDataReader(projects);
return projects;
}
private static void PopulateProjectsWithSqlDataReader(ICollection<Project> projects)
{
SqlDataReader sqlDataReader = null;
try
{
var sqlConnection = new SqlConnection(DBManager.DBConnection);
var sqlCommand = sqlConnection.CreateCommand();
sqlCommand.CommandText = DBManager.DBOwner + "sp_getCurrentProjects";
sqlCommand.CommandType = CommandType.StoredProcedure;
sqlConnection.Open();
sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.CloseConnection);
if (sqlDataReader == null) return;
while (sqlDataReader.Read())
{
var myProject = new Project
{
ProjectId = Convert.ToInt32(sqlDataReader["ProjectID"]),
Name = sqlDataReader["Name"].ToString(),
ProductName = sqlDataReader["ProductName"].ToString()
};
projects.Add(myProject);
}
}
finally
{
if (sqlDataReader != null) sqlDataReader.Close();
}
}
}
The conclusion I drew from this experiment: while I am accustomed to (and may prefer) to use an ORM tool like NHibernate to do my query retrievals in a repository, it is by no means my only option. Even plain old ADO.NET SqlDataReader can do the trick.
The primary goal is not which data access implementation to use, but instead the abstraction of the Domain Model, Repository, and application services (controller/presenter/web service).