With repository pattern should we define classes for every table in DAL or objects in business layer?

StackOverflow https://stackoverflow.com/questions/20853024

Question

How to implement repository pattern correctly in c# with entity framework when you have a larger database?

Should we define class for every table implementing Repository interface in DAL (data access layer) or we define objects like this in our business layer?

Repository<RetailerMarketplace> retailerMarketplaceRepo = null;
Repository<Marketplace> marketplaceRepo = null;
Repository<Product> productRepo = null;
Repository<OP_FLAGS> opFlagsRepo = null;
Repository<RetailerMarketplaceAttributeMapping> retailerMPAttributesMappingRepo = null;
Repository<EbayVariation> ebayVariationRepo = null;
Repository<ProductIsListed> productIsListedRepo = null;
Repository<Skus_OpFlags> skusOpFlagsRepo = null;

Currently i have defined objects like above but i am confused as to what is the correct approach of defining objects and using them either in DAL or business layer?

Was it helpful?

Solution

Don't create any Repository objects in your business layer. You should use a unit of work pattern together with your repository pattern. Your DAL should have a unit of work class that exposes only the necessary repositories as properties. This unit of work class acts as the only gateway between your business layer and data access layer.

For example, let's say I have two entities Foo and Bar structured like this:

public class Foo
{
    public int FooId { get; set; }
    public virtual ICollection<Bar> Bars { get; set; }
}

public class Bar
{
    public int BarId { get; set; }
    public int FooId { get; set; }
    public virtual Foo Foo { get; set; }
}

My UnitOfWork class might look like this:

public class UnitOfWork
{
    private Repository<Foo> foos;

    public Repository<Foo> Foos
    {
        get
        {
            if(foos == null)
                foos = new Repository<Foo>();
            return foos;
        }
    }

    ...
}

As far as defining a repository for every entity, you need to decide which ones you really need to include. For example my UnitOfWork doesn't include a Repository<Bar>. Perhaps I did this because I can get to all of the Bars through the linked property on their associated Foo and it doesn't make sense in my domain to look up a Bar on it's own. Bottom line: it all depends on your domain which repositories you expose. Just choose wisely.

This article was written by the ASP.NET/MVC team but the repository/unit of work principles in it are good practices for anything using Entity Framework. It's a good read whether you are working with MVC or not.

OTHER TIPS

EF has built-in repository objects, they are of type DbSet, which EF initializes on its own. So in your code example they would be like:

public DbSet<RetailerMarketplace> RetailerMarketplaces { get; set; }
public DbSet<Marketplace> MarketPlaces  { get; set; }

So why do you want to have an extra repository layer?

One reason may be is to be able to fake the repository object because DbSet does not provide an interface that can be used for mocking or faking. For example let us create a generic repository class, from an interface type of IRepostory. The class Repository in this case will encapsulate DbSet for whatever model T.

public interface IRepository<T> where T : class
{
    void Add(T model);
    void Edit(T model);
    void Delete(T model);
    T Get(object id);
    IQueryable<T> List();
}

public class Repository<T> : IRepository<T> where T : class
{
    DatabaseContext context;
    DbSet<T> dbSet;

    public Repository(DatabaseContext context)
    {
        this.context = context;
        this.dbSet = context.Set<T>();
    }

    public void Add(T model)
    {
        dbSet.Add(model);
    }

    public void Edit(T model)
    {
        dbSet.Attach(model);
        context.Entry(model).State = EntityState.Modified;
    }

    public void Delete(T model)
    {
        if (context.Entry(model).State == EntityState.Detached)
        {
            dbSet.Attach(model);
        }
        dbSet.Remove(model);
    }

    public T Get(object id)
    {
        return dbSet.Find(id);
    }

    public IQueryable<T> List()
    {
        return dbSet;
    }
}

To instantiate a repository

var context = new DbContext();
var repo = new Repository<Marketplace>(context);

The context above is the UoW object. Repo is the instantiated repository object. To create a fake object what you will need is to derive from IRepository.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top