views:

564

answers:

3

I am creating a sample, application to understand repository and factory method patterns together, because will use in a bigger project.

What i want to achieve is be able to make the website work with different ORM tools.

For example the website will have LINQ to SQL and Ado entity frame work classes implemented then using the factory method will use one of these ORMs "using config value" to load the data in the repository objects.

What i got till now is like the following

interface IRepository : IDisposable
{
  IQueryable GetAll();  
}

interface ICustomer : IRepository
{
}

public class CustomerLINQRepository : ICustomer
{
    public IQueryable GetAll()
    {
       // get all implementation using linqToSql
    }
    public void Dispose()
    {
      throw;
    }
    public IRepository GetObject()
    {
     return this;
    }
}


public class CustomerADORepository : ICustomer
{
    public IQueryable GetAll()
    {
       // get all implementation using ADO
    }
    public void Dispose()
    {
      throw new NotImplementedException();
    }
    public IRepository GetObject()
    {
     return this;
    }
}


// Filling a grid with data in a page
IRepository customers = GetCustomerObject();
this.GridView1.DataSource = customers.GetAll();
this.GridView1.DataBind();
////

public IRepository GetCustomerObject()
{
    return new CustomerLINQRepository(); // this will return object based on a config value later
}

But i can feel that there are a lot of design mistakes hope you can help me figure it out to get better design.

+1  A: 

I'm not sure on the naming of GetWanted. What exactly is wanted that you are getting? The name should be more descriptive, maybe GetCustomerRepository?

Is GetCustomerObject the same as GetWanted?

What is the throw for?

Robert Harvey
i renamed it to GetCustomerObject
Amr ElGarhy
changed the throw as well to "throw new NotImplementedException();"
Amr ElGarhy
Looking good...
Robert Harvey
ok, but look at this line: "IRepository customers = GetCustomerObject();" i am calling the customers using the IRepository interface, that means that all entities i will create later will call using IRepository, i hoped if i can call with ICustomer, ISupplier, ..., this is something wrong in the design or i am thinking the wrong way?
Amr ElGarhy
Well, when I use the repository pattern, I create CustomerRepository objects.
Robert Harvey
CustomerRepository is what will come from the GetCustomerObject function
Amr ElGarhy
Yes, but it's not returning ICustomerRepository, it's returning IRepository. See Matt Wrock's answer.
Robert Harvey
+1  A: 

Looks good for the most part. I have two comments:

  1. I would not call your customer Repository ICustomer. I would call it ICustomerRepository. That is more straight forward and and clarifies the repository based responsibility of the interface. ICustomer sounds like a DataObject encapsulating Customer data.
  2. Look into using an IOC container (google structure map, castle windsor or unity) instead of using the factory method. You could end up with alot of factory methods which could lead to confusion. Instead, it may be cleaner to have a single place in your code where your IOC wires up all of your repositories.
Matt Wrock
+1  A: 

My two cents:

A. I would add generic base repository class. a lot of the repository actions will be the same no matter what the type is. it can save you lots of typing.

B. I don't understand why your repositories are implementing the ICustomer interface. an interface for your Data Objects is a good practice but I don't think that your repository should implement it.

C. If there is a common implementation to your Data Objects, I would create a base class for them and restrict the repositories to work only with derived classes of the type.

I would do something like that:

public interface IEntity
{
     // Common to all Data Objects
}

public interface ICustomer : IEntity
{
     // Specific data for a customer
}


public interface IRepository<T, TID> : IDisposable where T : IEntity
{
     T Get(TID key);
     IList<T> GetAll();
     void Save (T entity);
     T Update (T entity);

     // Common data will be added here
}

public class Repository<T, TID> : IRepository<T, TID>
{
     // Implementation of the generic repository
}

public interface ICustomerRepository
{
     // Specific operations for the customers repository
}

public class CustomerRepository : Repository<ICustomer, int>, ICustomerRepository
{
     // Implementation of the specific customers repository
}

Usage:

CustomerRepository repository = new CustomerRepository();
IList<ICustomer> customers = repository.GetAll();
// Do whatever you want with the list of customers

That is the way that I implemented my DAL Using NHibernate. you can find some twists of that usage in "NHibernate in Action".

I would also recommend using some kind of IoC controller as Matt suggested.

Moshe Levi
nice, can you show me sample code to get data from customers "get collection of customers", i wrote it in my design like this IRepository customers = GetCustomerObject();this.GridView1.DataSource = customers.GetAll();this.GridView1.DataBind(); now how should i write it?
Amr ElGarhy
@Amr ElGarthy : I updated the answer to show some usage
Moshe Levi
in these 2 lines : 1- public class Repository<T, TID> : IRepository2- public class CustomerRepository : Repository<ICustomer>, ICustomerRepository It give me this error: Using the generic type 'TestApplication1.IRepository<T,TID>' requires '2' type arguments can you help me solve?
Amr ElGarhy
@Amr Elgarthy : Of course :) that's because I was missing the second type parameter (the object's key). that's what happen when you write C# code directly into stack overflow's text editor :) I Updated my answer once again.
Moshe Levi