b.logrythmik

{ dependency injection }

IDataContext - Using an Interface for the LinqToSql DataContext

As you know, I have recently become a huge fan of the Dependency Injection (DI) and Inversion of Control (IoC) patterns, but was stumped when trying to implement this pattern down to my data layer. I LOVE LinqToSQL, but I wasn't sure how I could make the Linq DataContext an abstract interface. I stumbled upon a great article discussing How to make the DataContext "Unit Testable". From this, I boiled down a version of an interface that was easy to implement in the DataContext.

An Interface for the DataContext: IDataContext

LinqToSql exposes Sql Server tables as theunmockable Table which is a sealed class. But LinqToSql namespace has an interface ITable which the Table type implements and that is easy to mock, also this ITable exposes InsertOnSubmit, InsertAllOnSubmit, DeleteOnSubmit, DeleteAllOnSubmit. So in our interface we exposed the ITable instead of that concrete Table which makes this partial Database class completely unit testable.

public interface IDataContext : IDisposable

{

    IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class;

 

    ITable GetEditable<TEntity>() where TEntity : class;

 

    void Insert<TEntity>(TEntity instance) where TEntity : class;

 

    void InsertAll<TEntity>(IEnumerable<TEntity> instances) where TEntity : class;

 

    void Delete<TEntity>(TEntity instance) where TEntity : class;

 

    void DeleteAll<TEntity>(IEnumerable<TEntity> instances) where TEntity : class;

 

    void SubmitChanges();

 

    int ExecuteCommand(string command, params object[] parameters);

 

    DbConnection Connection { get; }

}

As you can see, all the basic functions of the DataContext exist for your consuming class.

Implement that Sucker

Now we need to implement this interface in our DataContext. Right-click on your DBML file, and select "View Code".  This creates a partial class file for the DataContext. In it, you can implement the interface.

partial class SomeDataContext: IDataContext

{

    public virtual IQueryable<TEntity> GetQueryable<TEntity>() where TEntity : class

    {

        return this.GetTable<TEntity>();

    }

 

    public virtual ITable GetEditable<TEntity>() where TEntity : class

    {

        return this.GetTable<TEntity>();

    }

 

    public void Insert<TEntity>(TEntity instance) where TEntity : class

    {

        this.GetEditable<TEntity>().InsertOnSubmit(instance);

    }

 

    public void InsertAll<TEntity>(IEnumerable<TEntity> instances) where TEntity : class

    {

        this.GetEditable<TEntity>().InsertAllOnSubmit(instances);

    }

 

    public void Delete<TEntity>(TEntity instance) where TEntity : class

    {

        this.GetEditable<TEntity>().DeleteOnSubmit(instance);

    }

 

    public void DeleteAll<TEntity>(IEnumerable<TEntity> instances) where TEntity : class

    {

        this.GetEditable<TEntity>().DeleteAllOnSubmit(instances);

    }

}

Example Usage

Now, your consuming classes are free to use the DataContext as the Interface "IDataContext" which can be mocked in Unit Tests.

public class SomeController

{

    readonly IDataContext _DataContext;

 

    public SomeController(IDataContext dataContext)

    {

        _DataContext = dataContext;

    }

 

    public void DoSomething()

    {

        var foo = _DataContext.GetQueryable<Foo>()

                 .SingleOrDefault(f => f.FooId == 1);

 

    }

}

Conclusion

This demonstrates how you can make your DataContext an interface that is mockable and could be injected at runtime for DI. In the next article, I will show how you can create a generic repository using the IDataContext.