Posted by: Cirilo Meggiolaro | 05/7/2009

Tip of the day #205 – ASP.NET MVC – Architecture best practices – Loosely coupled data access

There are some architecture concepts that are not new but every time a product is launched it is worth to revisit some of them to make clearer to developers on how to implement them and for those that have just started a good opportunity to learn them.

We have heard and read a lot about separation of concerns in ASP.NET MVC and how model, controller and views interact between each other. Let’s talk today about the data access layer and how to decouple it from the Model and make it independent enough so you may change completely the implementation without affecting the core application code.

Scenario

You work as a developer and you are in charge of developing a new ASP.NET MVC web application for a client. The initial architecture strategy was to use LINQ to SQL as the data access framework. You start developing and after some time coding you receive an e-mail with requirements changes. After reading the new requirements document you figure out that you will have to make sure the application may be used by a client with a DB2 database. Your model classes are so tied to LINQ to SQL that you have to rewrite a lot of code to make it work properly.

Solution

One solution for the previous scenario is to decouple the model from the data access by developing against an interface instead of a concrete data access object. Creating an interface that dictates the operations and entities available makes your work pretty straightforward when developing a new data source class.

We are going to use the Repository pattern to achieve that.

To illustrate let’s assume we have an entity called Product as described below:

public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
public bool Active { get; set; }
}

The first step is to create an interface that identifies the operations available for the Product entity;

public interface IProductRepository
{
bool Create(Product product);
bool Update(Product product);
bool Delete(int id);
Product Get(int id);
List<Product> GetAll();
}

Let’s create a concrete class that will be responsible for handling the data access using an ADO.NET Entity Framework for example:

public class EntityProductRepository : IProductRepository
{
public bool Create(Product product)
{
// Creates a new product.
}

public bool Update(Product product)
{
// Updates an existing product.
}

public bool Delete(int id)
{
// Deletes an existing product from the database.
}

public Product Get(int id)
{
// Returns an instance of a Product.
}

public List<Product> GetAll()
{
// Returns a list with all products.
}
}

The structure of a second concrete class to handle the operations against a DB2 database would be pretty similar to the previous one. The following code snippet shows the DB2ProductRepository. The implementation code has been removed for brevity:

public class DB2ProductRepository : IProductRepository { }

The most important part is that since you have you interface defined and implemented you can use it from the controller class for example to request the operations to be executed. The following code shows the controller class accessing the data source via interface:

public class ProductController : Controller
{
private IProductRepository _repository;

public ProductController()
{
/// That is the only point you need to replace
/// if the data source changes.
_repository = new EntityProductRepository();
}

public ProductController(IProductRepository repository)
{
this._repository = repository;
}

public ActionResult Index()
{
return View(_repository.GetAll());
}

public ActionResult Create()
{
return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create([Bind(Exclude = “Id”)] Product productToCreate)
{
if (_repository.Create(productToCreate))
return RedirectToAction(“Index”);

return View();
}

public ActionResult Edit(int id)
{
return View(_repository.Get(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(Product productToEdit)
{
if (_repository.Update(productToEdit))
return RedirectToAction(“Index”);

return View();
}

public ActionResult Delete(int id)
{
return View(_repository.Get(id));
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Product productToDelete)
{
if (_repository.Delete(productToDelete.ID))
return RedirectToAction(“Index”);

return View();
}
}

If any implementations change in the data source class, the controller class code will not be affected by those changes. You may have noticed that one of the constructor overloads define the type of data source to use. If you want to change it to use the DB2 repository instead that is the only line of code you will have to change:

public class ProductController : Controller
{
private IProductRepository _repository;

public ProductController()
{
_repository = new DB2ProductRepository();
}

// Code removed for brevity.
}


Responses

  1. Very cool!

  2. What about talk about IOC container?

  3. very practical and excellent artical

  4. Hi,
    I read your articles on MVC and they are simply amazing. Thanks for sharing them.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: