Using interfaces for Domain entities (Part 1)

I’ve been doing a ton of work with ASP.NET MVC lately.  Which of course has me thinking how I design my code structure since MVC is all about separation of concerns.  I really like the idea of POCO (Plain Old Clr Objects) because it allows easily changing your access tier without having to rewrite a lot of your existing code.  After looking through Kigg’s source code I was given a fantastic idea bout how to handle this… just user interfaces.  So for this blog post I’ll demo how they do it so you don’t have to try to follow the IoC madness they implement.

To start off we need to create our projects.  I’m going to name this project IEntityDemo (original, I know).  I’ll be creating 2 other projects.  Both of which will be class library projects one which will contain our interface contracts and one that will contain the LinqToSql implementation.  The names of these projects will be IEntityDemo, IEntityDemo.Infrastructure (contracts, abstractions), and IEntityDemo.Repository.LinqToSql (implementation).

Here are some interfaces to get us started (in the IEntityDemo.Infrastructure project)

namespace IEntityDemo.Model
{
    public interface ICategory
    {
        int ID { get; set; }
        string Name { get; set; }
    }
}
namespace IEntityDemo.Model
{
    public interface IProduct
    {
        int ID { get; set; }
        string Name { get; set; }
        decimal Price { get; set; }

        ICategory Category { get; }
    }
}

These are our 2 entities we’ll be using and next is our repository contracts.

namespace IEntityDemo.Repository
{
    public interface IRepository<TEntity>
    {
        void Add(TEntity entity);
        void Delete(TEntity entity);

        ICollection<TEntity> GetAll();
    }
}
namespace IEntityDemo.Repository
{
    public interface IProductRepository : IRepository<IProduct>
    {
        IProduct GetByID(int id);
    }
}
namespace IEntityDemo.Repository
{
    public interface ICategoryRepository : IRepository<ICategory>
    {
        ICategory GetByID(int id);
    }
}

So far, simple.  Of course you can feel free to modify this as you see fit.  Next our gold nugget of DDD UnitOfWork.  Now I’m by no means saying I’m a DDD expert but I do try to use some of the ideas from the use of DDD and the idea of a unit of work is one of them.

namespace IEntityDemo.Repository
{
    public interface IUnitOfWork : IDisposable
    {
        void Commit();
    }
}

Next was the database layout, and I created it as so.

DBLayout

Just 2 tables with a basic FK.  And the LINQ to SQL layer…

LINQLayout

The only thing really left to do is our implementation using LINQ to SQL.  Normally I’m very strict about naming conventions but for this to work without jumping through hoops, I decided to add sql_ prefix to my tables.  Next in line is the Repository implementation.  One thing you have to remember to do is to setup your namespaces in your LINQ to SQL model.

LINQProps

    public class Repository<TAbstract, TConcrete> : IRepository<TAbstract>
        where TConcrete : class
    {
        public Repository(IEntityDemoDataContext db)
        {
            DB = db;
        }

        protected internal IEntityDemoDataContext DB { get; private set; }

        public void Add(TAbstract entity)
        { 
            DB.GetTable<TConcrete>().InsertOnSubmit(entity as TConcrete);
        }

        public void Delete(TAbstract entity)
        {
            DB.GetTable<TConcrete>().DeleteOnSubmit(entity as TConcrete);
        }

        public ICollection<TAbstract> GetAll()
        {
            return DB.GetTable<TConcrete>().Cast<TAbstract>().ToList();
        }

        protected internal IQueryable<TConcrete> GetTable()
        {
            return DB.GetTable<TConcrete>();
        }
    }
}

Of course you should abstract out the data context using a common interface but to keep this short I’m not.  Do as I say, not as I do!

Now it’s time for our Model implementation.

namespace IEntityDemo.Model
{
    public partial class sql_Category : ICategory
    {
    }
}
namespace IEntityDemo.Model
{
    public partial class sql_Product : IProduct
    {
        public ICategory Category
        {
            get { return sql_Category; }
        }
    }
}

Pretty slick, now we have concrete implementations of our repositories.

namespace IEntityDemo.Repository.LinqToSql
{
    public class CategoryRepository
        : Repository<ICategory, sql_Category>, ICategoryRepository
    {
        // TODO : Add IoC
        public CategoryRepository()
            : this(new IEntityDemoDataContext())
        {
        }

        public CategoryRepository(IEntityDemoDataContext db)
            : base(db)
        {
        }

        public ICategory GetByID(int id)
        {
            return GetTable().SingleOrDefault(c => c.ID == id);
        }
    }
}
namespace IEntityDemo.Repository.LinqToSql
{
    public class ProductRepository
        : Repository<IProduct, sql_Product>, IProductRepository
    {
        // TODO : Add IoC
        public ProductRepository()
            : this(new IEntityDemoDataContext())
        {
        }

        public ProductRepository(IEntityDemoDataContext db)
            : base(db)
        {
        }

        public IProduct GetByID(int id)
        {
            return GetTable().SingleOrDefault(p => p.ID == id);
        }
    }
}

This blog post is running pretty long so I’ve decided I’m going to turn this into a multi-part series.  To achieve this I’m leaving IoC/DI out for this one so as bad as this looks – it’s temporary.

Now it’s time to test out our efforts.

namespace IEntityDemo.Controllers
{
    [HandleError]
    public class HomeController : Controller
    {
        public HomeController()
            : this(new CategoryRepository(), new ProductRepository())
        {
        }

        public HomeController(ICategoryRepository categoryRepo,
                              IProductRepository productRepo)
        {
            CategoryRepo = categoryRepo;
            ProductRepo = productRepo;
        }

        private ICategoryRepository CategoryRepo { get; set; }
        private IProductRepository ProductRepo { get; set; }

        public ActionResult Index()
        {
            ViewData["Title"] = "Home Page";
            ViewData["Message"] = "Welcome to ASP.NET MVC!";

            var products = ProductRepo.GetAll();

            return View(products);
        }

        public ActionResult About()
        {
            ViewData["Title"] = "About Page";

            return View();
        }
    }
}

Again, this is temporary.  On that token let’s write some quick and dirty view code.

<% foreach (var product in ViewData.Model as
            IEnumerable<IEntityDemo.Model.IProduct>)
   {
       %><div><%= product.Category.Name %>: 
       <%= product.Name %> 
       <%= product.Price.ToString("C") %></div><%
   } %>

Mmm, I loves me some spaghetti code.

Now I know I some of you are thinking why would I go through all of that trouble just to write terrible code?  Well I realized this blog post was becoming overstuffed with info and I needed to turn.

1 Comment

Comments have been disabled for this content.