0

My goal is to load data from database and return a List . The following is my current code:

    public class CustomerRepository : ICustomerRepository
     {

        public IEnumerable<Customer> GetAll()
        {
            List<Customer> Customers = new List<Customer>();

            DataTable dtResult; 
            using (
        DbCommand cmd = TheDB.GetStoredProcCommand("spSelectAllCustomer"))
            {
                dtResult = TheDB.ExecuteDataSet(cmd).Tables[0];
            }


            Customers.AddRange( 
               from DataRow row in dtResult.Rows

               //*** How can I inject a new Customer instance in here?

               select new Customer() {
                          Name = row[0].ToString(), 
                          Email = row[1].ToString()
                     });

            return Customers;
        }
    }

I am no idea how to replace the new Customer with injection. Should I use container.Resolve? Is the container.Resolve a service locator, an anti-pattern?

Thanks.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
user3026964
  • 215
  • 1
  • 4
  • 7

1 Answers1

0

Use the Factory Pattern to create your instance(s). I would refactor your code as below.

Introduce a service which ochestrate calls to Repo and the factory you created. The service, I refer to as ICustomerProcessor. (ICusomerService is probably not the right choice of word here). This processor, you factory, and the repository is dependency injected, using your IUnityContainer. Some do call this as Facade.

public interface ICustomerProcessor {
    IEnumerable<Customer> GetAll();
}

The implementation of this service would simply call the Repository to get data, and a factory to create the entities.

public class CustomerProcessor : ICustomerProcessor {
    private readonly ICustomerFactory _customerFactory;
    private readonly ICustomerRepository _customerRepository;

    public CustomerProcessor(ICustomerRepository customerRepository, ICustomerFactory customerFactory)
    {
        _customerRepository = customerRepository;
        _customerFactory = customerFactory;
    }

    public IEnumerable<Customer> GetAll()
    {
        var data = _customerRepository.GetDataTable();
        return _customerFactory.CreateCustomers(data);
    }
}  

The repository only a representation of your database, and it just abstract your db call.

public class CustomerRepository : ICustomerRepository
{
    private readonly IDatabaseContext _database;

    public CustomerRepository(IDatabaseContext database) {
        _database = database;
    }


    public DataTable GetDataTable() {
        DataTable dtResult;
        using (DbCommand cmd = _database.GetStoredProcCommand("spSelectAllCustomer"))
        {
            dtResult = _database.ExecuteDataSet(cmd).Tables[0];
        }

        return dtResult;
    }
}

Note that IDatabaseContext does not require to Dependency Injected, it can be just a static context which you call the db. But the key idea is that your Repository encapsulate the database operations but nothing else.

With regards to Container.Resolve : You don't need this as your service are injected via the contructore inject. You domain object should not be dependency injected. They are just entities.

With regards to Service Locator. It is not the service locator is anti-patten, it is the way people use it make it an anti-pattern. In your case there absolutely no need to have a service locator in context. But in some case, you may use a service locator, when you cannot get hold of certain dependencies. But those cases are rare.

UPDATE :

Implementation of an ICustomerFactory:

public interface ICustomerFactory {
    IEnumerable<Customer> CreateCustomers(DataTable data);
}

public class CustomerFactory
{
    public IEnumerable<Customer> CreateCustomers(DataTable data)
    {
         return (from DataRow row in data.Rows
             select new Customer
             {
                 Name = row[0].ToString(), Email = row[1].ToString()
             }).ToList();
    }
}
Spock
  • 7,009
  • 1
  • 41
  • 60
  • Could you also demonstrate how to implement the CusotmerFactory.CreateCustomers(data)? I think that I still have to use "new Customer()" to create Customers in the Factory. Thanks you. – user3026964 Dec 07 '13 at 22:49
  • @user3026964 I have updated my answer to include the implementation of ICustomerFactory. Also remember, as you said you need "new Customer()", BUT it has been abstracted out the factory. Which is good because you decouple that concern from the repo itself. – Spock Dec 07 '13 at 22:53
  • Valve1900: Thanks for the quick reply. This way adds a new Factory class, it should be a good thing as Single Responsibility Principle. But now the coupling is moved into CustomerFactory class. Or, it is fine to couple with an entity objects. It could be abnormal to have multiple implementation of a domain entity. It’s not necessary to have an ICusotmer interface and inject it to the factory, isn’t it? – user3026964 Dec 07 '13 at 23:51
  • Valve1900: I wonder if I had different ICustomer implementations, such as I have to build multiple website for different clients. Customer classes will include different business rules for each clients. How can I implement the factory in this case? Should I create multiple ICustomerFactory, so that each factory creates a type of Customer respectively? And still in every factory class, I could use “new AnotherCustoemr()” to create IEnumerable instance? – user3026964 Dec 07 '13 at 23:52
  • If you read the factory pattern, you would understand it is perfectly fine to create entities using the factory class. "CustomerFactory" is just and example, but you can call whatever you want. You don't need multiple factories. It is an overkill. Something like ApplicationEntityFactory, which would be more generic, and you can use this factory to create entities that are not Customers as well. Btw similar questions have been answered in SO, so you can understand this pattern more. – Spock Dec 08 '13 at 01:00