1

I assigned a POC project to someone where I asked to implement both Command Query Responsibility Segregation, Inversion of Control (with Dependency Injection) and Repository pattern. “Someone” gave me a POC solution project but I am not sure whether this is the way it is done. I will brief here about the POC project

  • The project is a simple 3-tier application – the Presentation Layer (PL), the Business Logic Layer (BLL) and the Data Access Layer (DAL); each tier being a separate project
  • The Presentation Layer is a Web Application, the BLL and DAL are class library projects
  • In the Business Layer, there are defined Repository Interfaces. The reference of BLL library is added to DAL project and inside the DAL project there are concrete classes that implement the Repository Interfaces. This is how Inversion of Control is applied
  • Since Command-Query-Responsibility-Segregation is done, the repository interfaces in the Business Layer only declare Add/Update and Delete methods. For read, there are “Read” interfaces directly in the DAL and in the DAL there are concrete classes that implement these interfaces.
  • The Presentation Layer contains reference to both the BLL library and the DAL library. Calls to Add/Update/Delete are routed through the BLL to the DAL while any read is done directly from the DAL. I believe this conforms to Command-Query-Responsibility-Segregation concept of bypassing the BLL for doing reads.

Here is an illustration of how this is all setup. There are three projects

  • NW.Web
  • NW.Business
  • NW.DataAccess

Below is a snapshot of code in the different layers.

-- NW.Web --

// A class in the Presentation Layer
public class CustomerPage 
{

    // Business layer Interface from  NW.Business namespace
    private ICustomerBusiness ICustB;

    //DAL Read interface from NW.DataAccess.Read namepsace
    private ICustomerRead<Guid> ICustR;

    //Constructor for the Customer Page that uses Constructor Injection
  public CustomerPage(ICustomerBusiness ICustB, ICustomerRead<Guid> ICustR)
    {
        this.ICustB = ICustB;
        this.ICustR = ICustR;
    }
}

-- NW.Business --

//Declaration of business interface in the Business Layer
interface ICustomerBusiness
{
    void Persist();
}

// A class in the Business Layer that implements the business interface
public class Customer: ICustomerBusiness 
{
    //Repository interface object that will be injected by Constructor Injection.
    private ICustomerRepository ICustRep;

    public Customer(ICustomerRepository ICustRep)
    {
        this.ICustRep = ICustRep;
    }

    public void Persist()
    {

            ICustRep.AddOrUpdate();

    }
}

//Declaration of Repository interface in the Business Layer
public interface ICustomerRepository
{
    void AddOrUpdate();
    void Delete();
}

-- NW.DataAccess--

public class CustomerRepository : ICustomerRepository
{

    public void AddOrUpdate()
    {
        //implementation of Add or Update
    }

    public void Delete()
    {
        //implementation of Delete
    }
}

//A Read interface in the Data Access Layer
interface ICustomerRead<T>
{
   // A read is returned as DTO since in Database this may map to more than 1 table
    CustomerDTO GetCustomerDetails(T id);
}

// An implementation of the Read Interface in the Data Access Layer
namespace NW.DataAccess.Read
{
    public class CustomerRead<T> : ICustomerRead<T> 
    {

        public CustomerDTO GetCustomerDetails(T id)
        {
           //implementation here
        }
    }
}

My gut feeling is that there is something wrong here. It seems CQRS or at least the above implementation does not address some requirements

  • The Customer Business object (Customer class) may need to read from Database for its internal purpose (like initializing variables etc). With read directly defined in DAL layer, the only way to do this would be to reference the DAL dll in the BLL. But this would create circular reference and go against the IOC that is done
  • What happens when there is some common Read requirement across all business objects ?
6
  • CQRS (Command Query Responsibility Segregation) is not the same as CQS (Command Query Separation).
    – rmac
    Commented Jan 28, 2013 at 16:49
  • Thanks for pointing the mistake. I have corrected the question
    – devanalyst
    Commented Jan 30, 2013 at 8:46
  • You still mention both in the question. You "assigned someone to create a CQS implementation", and then you question if it adheres to CQRS. That doesn't make sense. I don't know what I'm supposed to answer here. You need to clarify what your question is.
    – rmac
    Commented Jan 30, 2013 at 18:34
  • I am sorry for the confusion. CQS is mentioned inadvertently. It should be CQRS. I have made corrections.
    – devanalyst
    Commented Jan 31, 2013 at 4:03
  • You may try to use the Unit Of Work Pattern : msdn.microsoft.com/en-us/magazine/dd882510.aspx
    – Pak
    Commented Apr 1, 2014 at 17:55

1 Answer 1

1

I think you need to create an interface in the BLL that holds your connection (datacontext, sqlConnection, or whatever). That concrete class would then go into the DAL. On initialization you would include the connection string.

When you do a data read function you would pass along the datacontext or whatever you used for the connection. You could also send the connection along upon initialization.

Does that make sense? You can look at the link below to get an idea on the data access interface.

http://vbsoftwaredeveloper.blogspot.com/2013/05/4-tier-ioc-application-converted-tier.html

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.