Generic LinqtoSql Repository

There are some solutions base on Expression and reflection, I think this one is very simple and flexible. Only drawback is decedents must implement IsNew and FetchById, which I think it’s a good thing, because Entity from LinqToSql doesn’t  support inheritance very well.

I made some changes to it to make it support stateless better. The service layer can use TransactionScope to manage transaction (throw exception to rollback).


using System;
using System.Data.Linq;
using System.Linq;

namespace data
{
    public abstract class Repository<T> where T : class
    {
        private readonly IDataContextProvider _conn;

        protected Repository(IDataContextProvider conn)
        {
            _conn = conn;
        }

        public virtual IQueryable<T> GetAll(Func<T, bool> exp)
        {
            var dc = _conn.GetContext();
            // Can not dispose it due to deferred execution
//            using (var dc = _conn.GetContext())
//            {
                return dc.GetTable<T>().Where(exp).AsQueryable();
//            }
        }

        public T Single(Func<T, bool> exp)
        {
            using (var dc = _conn.GetContext())
            {
                return dc.GetTable<T>().Single(exp);
            }
        }

        public void Save(T objectToSave)
        {
            using (var dc = _conn.GetContext())
            {
                if (IsNew(objectToSave))
                {
                    dc.GetTable<T>().InsertOnSubmit(objectToSave);
                }
                else
                {
                    dc.GetTable<T>().Attach(objectToSave, true);
                }
                dc.SubmitChanges();
            }
        }

        /// <summary>
        ///
        /// </summary>
        /// <example>
        /// <code>
        ///      return objectToSave.Id == 0;
        /// </code>
        /// </example>
        /// <param name="objectToSave"></param>
        /// <returns></returns>
        public abstract bool IsNew(T objectToSave);

        public void Delete(T objectToDelete)
        {
            using (var dc = _conn.GetContext())
            {
                dc.GetTable<T>().Attach(objectToDelete, true);
                dc.GetTable<T>().DeleteOnSubmit(objectToDelete);
                dc.SubmitChanges();
            }
            return;
        }
    }

    public class DataContextProvider : IDataContextProvider
    {
        public DataContext GetContext()
        {
            return new DataClasses1DataContext {Log = Console.Out};
        }
    }

    public interface IDataContextProvider
    {
        DataContext GetContext();
    }
}

        [Test]
        [ExpectedException(typeof(NormalRollbackException))]
        public void should_save_modified_object()
        {
            using (new TransactionScope())
            {
                var objectToSave = _systemUnderTest.FectchById(1);
                string newDescription = "sdfd:" + new Random().Next();
                objectToSave.Description = newDescription;

                _systemUnderTest.Save(objectToSave);

                var check = _systemUnderTest.FectchById(objectToSave.Id);
                Assert.AreEqual(newDescription, check.Description);

                throw new NormalRollbackException();
            }
        }
Advertisements