When developing applications using a layered architecture, one of the problems that arise is how to pass information through tiers, in particular between the data and business layer. Let's assume that we have an employee entity that accesses an employee data class to retrieve the information from the data store. Employee is in our business assembly and our repository and data layer is in our data assembly. The repository can and should ideally be in a separate assembly, however for simplicity we will keep it in the same for this example since it doesn't affect the situation.
Since BusinessLayer calls EmployeeRepository to get an instance of a particular employee, BusinessLayer needs to reference DataLayer. In turn, since DataLayer creates an instance of type Employee, DataLayer needs to reference BusinessLayer. However, this causes a circular reference problem.
One solution to the problem would consist of using a DTO (Data Transfer Object) in a third assembly to transfer information. BusinessLayer will now reference DataTransfer, as will DataLayer, avoiding a circular reference.
This however adds a new class to our domain which isn't strictly necessary. It also means that we now have to copy values from EmployeeDTO to an Employee class, since EmployeeRespository returns type EmployeeDTO.
Using interfaces and generics
In order to avoid the above situation, we can make use of interfaces and generics to solve the problem. Instead of having EmployeeDTO, we create an interface IEmployee that Employee implements. This interface only declares the properties employees will have. Methods are particular to the business needs and are only present in the actual Employee class.
Let's look at the resulting code.
The EmployeeRepository code should look something like the following
However, we now face a new problem. FindEmployee is returning an EmployeeDL. To do so, it's calling EmployeeDL. EmployeeDL cannot reference BusinessLayer, since if it does, we'd be in the same boat (circular reference). EmployeeDL should return an IEmployeeDL. This seems simple enough, except it's not possible to create instances of interfaces for obvious reasons. This leaves us with the problem of returning an instance of EmployeeDL, and to do this we make use of generics. For this, we implement EmployeeDL in the following way
We are forcing the generic type to implement IEmployee and also have a parameterless constructor. This allows us to create new instances of the type and also assign the properties of an employee object. The only thing left to do is change the EmployeeRepository to use this code.
We now have a clear separation of layers without the need of introducing additional classes to our domain, complicating the scenario when it's not completely required.
Note: The point of this post is to show you how to pass data between tiers without using auxiliary objects, whether this may be a DTO class, an XML file, a DataTable or DataSet or whatever else you might like. I'm not debating which method is better, although I have a preference for the one shown in this post.