Implementing the Repository Pattern with LINQ-to-SQL
page 3 of 4
by Liam McLennan
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 29713/ 57

LINQ-to-SQL

LINQ is a strongly typed way of querying data. LINQ-to-SQL is a dialect of LINQ that allows the querying of a SQL Server database. It also includes object/relational mapping and tools for generating domain model classes from a database schema. LINQ is an excellent addition to object/relational mappings tools because it facilitates strongly typed queries.

Listing 1

IList<Shape> threeSidedShapes = _genericShapeRepository.FindAll(
    shape => shape.NumberOfSides == 3).Take(5).ToList(); 

IRepository<T>

The generic interface IRepository<T> defines the methods that are required on each repository.

Listing 2

public interface IRepository<T> where T : class
{
    /// <summary>
    /// Return all instances of type T.
    /// </summary>
    /// <returns></returns>
    IEnumerable<T> All();
 
    /// <summary>
    /// Return all instances of type T that match the expression exp.
    /// </summary>
    /// <param name="exp"></param>
    /// <returns></returns>
    IEnumerable<T> FindAll(Func<T, bool> exp);
 
    /// <summary>Returns the single entity matching the expression. 
    /// Throws an exception if there is not exactly one such entity.</summary>
    /// <param name="exp"></param><returns></returns>
    T Single(Func<T, bool> exp);
 
    /// <summary>Returns the first element satisfying the condition.</summary>
    /// <param name="exp"></param><returns></returns>
    T First(Func<T, bool> exp);
 
    /// <summary>
    /// Mark an entity to be deleted when the context is saved.
    /// </summary>
    /// <param name="entity"></param>
    void MarkForDeletion(T entity);
 
    /// <summary>
    /// Create a new instance of type T.
    /// </summary>
    /// <returns></returns>
    T CreateInstance();
 
    /// <summary>Persist the data context.</summary>
    void SaveAll();
} 

Repository<T>

IRepository<T> is implemented by a generic repository base class, Repository<T>. Repository<T> is a base implementation that provides data access functionality for all entities. If an entity (T) does not require a specialized repository then its data access will be done through Repository<T>.

Listing 3

public class Repository<T> : IRepository<T> 
    where T : class
{
    protected IDataContextFactory _dataContextFactory;
 
    /// <summary>
    /// Return all instances of type T.
    /// </summary>
    /// <returns></returns>
    public IEnumerable<T> All()
    {
        return GetTable;
    }
 
    /// <summary>
    /// Return all instances of type T that match the expression exp.
    /// </summary>
    /// <param name="exp"></param>
    /// <returns></returns>
    public IEnumerable<T> FindAll(Func<T, bool> exp)
    {
        return GetTable.Where<T>(exp);
    }
 
    /// <summary>See IRepository.</summary>
    /// <param name="exp"></param><returns></returns>
    public T Single(Func<T, bool> exp)
    {
        return GetTable.Single(exp);
    }
 
    /// <summary>See IRepository.</summary>
    /// <param name="exp"></param><returns></returns>
    public T First(Func<T, bool> exp)
    {
        return GetTable.First(exp);
    }
 
    /// <summary>See IRepository.</summary>
    /// <param name="entity"></param>
    public virtual void MarkForDeletion(T entity)
    {
        _dataContextFactory.Context.GetTable<T>().DeleteOnSubmit(entity);        
    }
 
    /// <summary>
    /// Create a new instance of type T.
    /// </summary>
    /// <returns></returns>
    public virtual T CreateInstance()
    {
        T entity = Activator.CreateInstance<T>();
        GetTable.InsertOnSubmit(entity);
        return entity;
    }
 
    /// <summary>See IRepository.</summary>
    public void SaveAll()
    {
        _dataContextFactory.SaveAll();
    }
 
    public Repository(IDataContextFactory dataContextFactory)
    {
        _dataContextFactory = dataContextFactory;
    }
    
    #region Properties
 
    private string PrimaryKeyName
    {
        get { return TableMetadata.RowType.IdentityMembers[0].Name; }
    }
 
    private System.Data.Linq.Table<T> GetTable
    {
        get { return _dataContextFactory.Context.GetTable<T>(); }
    }
 
    private System.Data.Linq.Mapping.MetaTable TableMetadata
    {
        get { return _dataContextFactory.Context.Mapping.GetTable(typeof(T)); }
    }
 
    private System.Data.Linq.Mapping.MetaType ClassMetadata
    {
        get { return _dataContextFactory.Context.Mapping.GetMetaType(typeof(T)); }
    }
 
    #endregion
}

IShapeRepository & ShapeRepository

It is usually desirable to provide more specialized repositories for entity classes. If our domain includes a shape entity, we might like to have a ShapeRepository with a RetrieveByNumberOfSides(int sideCount) method. Such a class would be exposed to consumers as a specialized interface IShapeRepository.

Listing 4

    public interface IShapeRepository : IRepository<Shape>
    {
        Shape RetrieveByNumberOfSides(int sideCount)
    }
    public class ShapeRepository : Repository<Shape>, IShapeRepository
    {
        public Shape RetrieveByNumberOfSides(int sideCount)
        {
            return FindAll(shape => shape.NumberOfSides == sideCount);
        }
    }

Usage

We now have a fully functioning, decoupled repository implementation. A class might use the repositories as follows:

Listing 5

public class ApplicationService
{
    private IRepository<Shape> _genericShapeRepository;
    private IShapeRepository _specializedShapeRepository;
 
    public ApplicationService(IRepository<Shape> genericShapeRepository, 
      IShapeRepository specializedShapeRepository)
    {
        _genericShapeRepository = genericShapeRepository;
        _specializedShapeRepository = specializedShapeRepository;
    }
 
    public void DoSomethingWithTheGenericRepository()
    {
        IList<Shape> threeSidedShapes = _genericShapeRepository.FindAll(
            shape => shape.NumberOfSides == 3).ToList();
 
        _genericShapeRepository.MarkForDeletion(threeSidedShapes[0]);
        _genericShapeRepository.SaveAll();
    }
 
    public void DoSomethingWithTheSpecializedRepository()
    {
        IList<Shape> threeSidedShapes = 
            _specializedShapeRepository.RetrieveByNumberOfSides(3).ToList();
 
        _specializedShapeRepository.MarkForDeletion(threeSidedShapes[0]);
        _specializedShapeRepository.SaveAll();
    }
 
}

View Entire Article

User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-26 9:24:35 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search