Linq to SQL Tutorial – Base Repository/Business Logic wrapper

Before Linq to SQL I always separated out my Entities, Data Access Layer and Business Logic Layer.  With Linq to SQL it’s a little different as I feel the generated classes are kind of like the Entity and Data Access Layer combined.  Rather than using the generated entities directly it is still good practice to have a Business Logic Layer.  In this example I am using the term Repository which is an aspect of Domain-Driven Design.

Each entity will likely need it’s own repository object, as there will business logic that is specific for that entity, but there will be logic that is shared between all entities so it is worth creating a base object for this.

I have created a generic abstract class called RepositoryBase which has a constraint for EntityBase which is the base entity class I created in my Set inheritance modifiers with SQLMetalpost.  This ensures that the repositories can only be used with the objects created by Linq to SQL.

To handle my DataContext I am creating an instance of it in the constructor and keeping this instance for the life of the object.  For this reason my base repository implements IDisposable to handle disposing the DataContext.

Here is the code for my base repository:


public abstract class RepositoryBase<T> : IDisposable where T : EntityBase
{
    private UniversityDataContext _context;

    public RepositoryBase()
    {
        _context = new UniversityDataContext(ConfigurationManager.ConnectionStrings["UniversityConnectionString"].ConnectionString);
    }

    public UniversityDataContext Context
    {
        get
        {
            return _context;
        }
    }

    public List<T> GetAll()
    {
        return _context.GetTable<T>().ToList();
    }
    public T GetByID(int id)
    {
        return _context.GetTable<T>().FirstOrDefault(e => e.ID.Equals(id));
    }

    public int Count()
    {
        return _context.GetTable<T>().Count();
    }

    public void Save(T entity)
    {
        if (entity.IsNew)
        {
            _context.GetTable<T>().InsertOnSubmit(entity);
        }
        else
        {
            _context.GetTable<T>().Attach(entity, true);
        }

        _context.SubmitChanges();
    }

    public void Delete(T entity)
    {
        if (!entity.IsNew)
        {
            _context.GetTable<T>().Attach(entity);
            _context.GetTable<T>().DeleteOnSubmit(entity);
            _context.SubmitChanges();
        }
    }

    public void Dispose()
    {
        if (_context != null)
        {
            _context.Dispose();
        }
    }
}

You can see it contains methods that are relevant for all entities.  A method to get all entities, a method to get all entities by ID which I can do due to ID being a virtual member in my EntityBase class which is overridden by each entity.  It also has generic methods for saving and deleting which will work for any of the entities.  There will be a lot more logic that could go into this base class, but for now this just shows the basics.

Using this class you can derive separate repositories for each entity. I have a public property for the Context which allows any derived classes to use the DataContext instance.  Here is my implementation for StudentRepository which adds a couple of student specific methods:


public class StudentRepository : RepositoryBase<Student>
{
    public List<Student> GetByForename(string forename)
    {
        return Context.Students.Where(s => s.Forename.Equals(forename, StringComparison.CurrentCultureIgnoreCase)).ToList();
    }

    public List<Student> GetBySurname(string surname)
     {
        return Context.Students.Where(s => s.Surname.Equals(surname, StringComparison.CurrentCultureIgnoreCase)).ToList();
    }
}

Using this derived class I could use any of the base methods:

StudentRepository rep = new StudentRepository();
Student s = rep.GetByID(1);
s.Forename = "Joseph";
rep.Save(s);
gvStudents.DataSource = new StudentRepository().GetAll();
gvStudents.DataBind();

I could also use any of the entity specific methods:

StudentRepository rep = new StudentRepository();
List<Student> students = rep.GetByForename("Joseph");
foreach (Student s in students)
{
    rep.Delete(s);
}

To explicitly dispose of the object and the underlying DataContext I could do the following:

using (StudentRepository rep = new StudentRepository())
{
    List<Student> students = rep.GetByForename("Joseph");
    foreach (Student s in students)
    {
        rep.Delete(s);
    }
}
Posted on by Joe in C#, Linq

2 Responses to Linq to SQL Tutorial – Base Repository/Business Logic wrapper

  1. Reynerio Sarmiento

    Hey Joe, Nice tut. man I will give this code a try. I’ve been looking for something like this for quite a while now…

    Thanks.

  2. Joe

    Thanks Reynerio

    Check out my post on ObjectDataSource binding using this method; I’ve just added the sourcecode:

    http://www.joe-stevens.com/2009/07/15/linq-to-sql-objectdatasource-binding-with-paging-and-sorting/

    Joe

Add a Comment