views:

245

answers:

2

Hi there.

I'm trying to write a generic repository for my Entity Framework based application. Here's my prototype code:

Interface

public interface IDomainRepository
    {
        T GetById<T>(int id, Expression<Action<T>> idx)
    }

and the repository:

public class DomainRepository : IDomainRepository
    {
        private readonly DatabaseDataContext _ctx;

        public DomainRepository(DatabaseDataContext ctx)
        {
            _ctx = ctx;
        }

        public T GetById<T>(int id, Expression<Action<T>> idx)
        {
            return _ctx.GetTable(typeof (T)).SingleOrDefault(idx);
        }
    }

The above is test code which doesn't work. But what I'd like to be able to do is this:

var repository = new DomainRepository(myContext);

var client = repository.GetById<tbl_Clients>(23, c => c.clientId);

So basically I want to get a client entity from the database by passing in the id plus a lambda telling GetById what the id column is. Also, I have no idea how I would execute the lambda using the passed id.

Can someone help me with this?

EDIT:

I'm really close. I've changed GetById:

public T GetById<T>(int id, Expression<Func<T, object>> idx)

and I can now call it like this:

var g = repository.GetById<tbl_Client>(23, c => c.cl_id);

but I don't know how to use idx and check it's value against the passed id:

 public T GetById<T>(int id, Expression<Func<T, object>> idx)
        {
            //var col = idx.Compile().Invoke(T);
           // How do I check if the column passed to "idx" is equal to id?

            return default(T);
        }

EDIT: Think I got this working now. Here is my entire code, plus test:

public interface IDomainRepository
    {
        T GetById<T>(int id, Expression<Func<T, object>> idx) where T : class;

        IEnumerable<T> GetAll<T>() where T : class;
        IEnumerable<T> Query<T>(Expression<Func<T, bool>> filter) where T : class;
        IEnumerable<T> Query<T>(ISpecification<T> filter) where T : class;

        void Add<T>(T entity) where T : class;
        void Delete<T>(T entity) where T : class;
        Table<T> GetTable<T>() where T : class;
    }

public class DomainRepository : IDomainRepository
    {
        private readonly DatabaseDataContext _ctx;

        public DomainRepository(DatabaseDataContext ctx)
        {
            _ctx = ctx;
        }

        public T GetById<T>(int id, Expression<Func<T, object>> idx) where T : class
        {
            return (from i in GetAll<T>()
                    let h = idx.Compile().Invoke(i)
                    where Convert.ToInt32(h) == id
                    select i).SingleOrDefault();
        }

        public IEnumerable<T> GetAll<T>() where T : class
        {
            return GetTable<T>().ToList();
        }

        public IEnumerable<T> Query<T>(Expression<Func<T, bool>> filter) where T : class
        {
            return GetTable<T>().Where(filter);
        }

        public IEnumerable<T> Query<T> (ISpecification<T> filter) where T : class
        {
            return GetTable<T>().Where(filter.Predicate);
        }

        public void Add<T> (T entity) where T : class
        {
            GetTable<T>().InsertOnSubmit(entity);
        }

        public void Delete<T> (T entity) where T : class
        {
            GetTable<T>().DeleteOnSubmit(entity);
        }

        public Table<T> GetTable<T>() where T : class
        {
            return _ctx.GetTable(typeof(T)) as Table<T>;
        }
    }


var repository = new DomainRepository(_ctx);

var g = repository.GetById<tbl_Client>(1, c => c.cl_id);

I'll keep testing this to see if it's OK.

Cheers. Jas.

A: 

You could just expose the IQueryable through layers.

IQueryable Users {get;}

So you can do something like this in your ui code:

BLLContext.Users.Where(c => c.Username == "foo");

BLLContext will have an underlying DAL context which exposes the IQueryable.

Matteo Mosca
Thanks for your suggestion, but I want the repository to be generic, thus it can't know about "Users" in a concrete manner. Cheers anyway.
Jason Evans
A: 

Hi there.

OK, I think I have the final version, will need a bit more testing though:

public T GetById<T>(int id, Func<T, int> idx) where T : class
        {
            return (from i in GetAll<T>()
                    where idx(i) == id
                    select i).SingleOrDefault();
        }

Cheers. Jas.

Jason Evans
Check SQL generated by this method. As far as I understand it may result in materializing entire table and applying Linq to Objects.
Yury Tarabanko