0

I am trying to design my application architecture using ado.net with sql server. I am consider to use threee layers as follows:

Presentation Layer -> Business Layer (BAL) -> Data access Layer (DAL)

Entities for sample objects like Employee, Department etc..

I am trying to use interfaces as a contracts for some of my classes. My current issue is that i see some of the methods are common between BAL and DAL objects like: Add, Remove, GetAll therefore i decided to create interfaces to implement such things however when using from BAL classes i need to have it like void Add(Employee) but in DAL void Add(string name); therefore i splitted almost same interfaces on DAL and BAL (i do not like it because it seems to be somehow duplicated). Next issue is when want to use my code at the StickTogether class i am not able to call for instance _employee.Department = _department; I know it's because Department property should be in RepositoryBal interface but then simple entity Department would need to implement such interface which i dont want to do because as far as i read entities are just simple repeesentation of specific object. Could you tell me - best show on example how you would create such architecture or modify my to have something better than what i have right now. Below find my full code i am working on. How this could be fixed?

Please note i also start to prepare this code for dependency which will be helpfull for moc tests.

Appreciate your answers with proposed fixed solution based on my code.

public class StickTogether
{
    private readonly IRepositoryBal<Employee> _employee;
    private readonly IRepositoryBal<Department> _department;

    public StickTogether(IRepositoryBal<Employee> employee, IRepositoryBal<Department> department)
    {
        _employee = employee;
        _department = department;
    }

    public void Create()
    {
        _employee.Add(new Employee());
        _department.Add(new Department());
        _employee.Department = _department; //not accessible which has a sense
    }
}

public interface IEntity
{
    int Id { get; set; }
}

public class Employee : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; } 
    public Department Department { get; set; }
}

public class Department : IEntity
{
    public int Id { get; set; }
    public string Name { get; set; }      
}

public interface IRepositoryDal<T> where T : IEntity
{
    void Add(string name);
    void Delete(int id);
    IEnumerable GetAll();
}

public interface IRepositoryBal<T> where T : IEntity
{

    void Add(T entity);
    void Delete(T entity);
    IEnumerable<T> GetAll();
}

internal class DepartmentBal : IRepositoryBal<Department>
{
    private readonly IRepositoryDal<Department> _departmentDal;

    public DepartmentBal(IRepositoryDal<Department> department)
    {
        _departmentDal = department;
    }

    public void Add(Department entity)
    {
        _departmentDal.Add(entity.Name);
    }

    public void Delete(Department entity)
    {
        _departmentDal.Delete(entity.Id);
    }

    public IEnumerable<Department> GetAll()
    {
        return (IEnumerable<Department>)_departmentDal.GetAll();
    }
}

public class DepartmentDal : IRepositoryDal<Department>
{

    public void Add(string name)
    {
        //call sql server stored procedure to add department;
    }

    public void Delete(int id)
    {
        //call sql server stored procedure to delete department by id;
    }

    public IEnumerable GetAll()
    {
        //call sql server stored procedure to return all employees;
        return null;
    }
}

internal class EmployeeBal : IRepositoryBal<Employee>
{
    private readonly IRepositoryDal<Employee> _employeeDal;

    public EmployeeBal(IRepositoryDal<Employee> employee)
    {
        _employeeDal = employee;
    }

    public void Add(Employee entity)
    {
        _employeeDal.Add(entity.Name);
    }

    public void Delete(Employee entity)
    {
        _employeeDal.Delete(entity.Id);
    }

    public IEnumerable<Employee> GetAll()
    {
       return (IEnumerable<Employee>) _employeeDal.GetAll();
    }
}

public class EmployeeDal : IRepositoryDal<Employee>
{

    public void Add(string name)
    {
        //call sql server stored procedure to add employee;
    }

    public void Delete(int id)
    {
        //call sql server stored procedure to delete employee by id;
    }

    public IEnumerable GetAll()
    {
        //call sql server stored procedure to return all employee;
        return null;
    }
}
Sefe
  • 12,811
  • 5
  • 36
  • 50
DinoDin2
  • 121
  • 10
  • It think the business layer should just be joins of the data layer. The Data Layer must be the same as the tables in the database. The presentation is just putting the data into reports and views. The business layer should just be an interface between the presentation and data layers. The business layer may also do calculating of the data for monthly and weekly reports. – jdweng Aug 31 '18 at 09:45
  • @jdweng yes that's what i know so far. The problem is resisting in my techincal implementation as i describe. I am still looking for a way to fix my current code. – DinoDin2 Aug 31 '18 at 09:48
  • I would have a DepartmentBussiness Class that do the deleting and balances instead of two classes and have methods to perform the tasks. Likewise with the Employee Class. – jdweng Aug 31 '18 at 10:01
  • @jdweng Appreciate answer showing this approach if possible certainly. – DinoDin2 Aug 31 '18 at 10:31
  • Not to sound rude, but 'just implement the damn thing' and see what fits. We can theory-craft for days and still have no idea how your perfect jewel will be used on the battlefield, and nomatter your choice, you'll wish you chose differently :P – Davesoft Aug 31 '18 at 10:35
  • I think your thinking is too complicated. Check if you really need to define interfaces (especially in the DAL). And I would strongly recommend separate interfaces/classes for Business and DAL as they tend to diverge quickly (as you have noticed) and their unifying factor is not relevant since you are supposed to keep layers separate. – Sefe Aug 31 '18 at 10:37
  • Insteald of `void Add(Employee)` vs `void Add(string name)`, how about `void Add(IEmployee)`. i.e. Have an interface describing the properties of an employee; which you can then use for either method; in one taking the Employee object whole, in the other accessing the Name property of the employee object as needed. – JohnLBevan Aug 31 '18 at 10:40
  • First question, why are you using a 3 layer pattern? Many people just do this by default. But there is no real need to always have 3 layers. In fact I subscribe to the opinion that [3 layer is an anti pattern](http://devmethodologies.blogspot.com/2012/10/the-layer-anti-pattern.html). It sounds like what you really want is dependancy injection. If you want to use DI I would recommend implementing a framework, I'd suggest [simpleInjector](https://simpleinjector.org/index.html) – Liam Aug 31 '18 at 10:40
  • 1
    Question is too vague and has multiple issues. I would recommend to first go with simple approach for example, remove all interfaces and go with simple classes and divide the system into layers. Then find out the common parts and start implementing abstract classes / interfaces. Then you might come with some proper question which can be answered. – sallushan Aug 31 '18 at 10:45
  • @sallushan the problem is if both dal and bal using Add/Remove/GetAll but the one diffrence is arguments - for bal it will take e.g Add(Employee employee) and DAL Add(name as string) i have to make similar to interfaces separatly for dal and bal... I dont like it. – DinoDin2 Sep 03 '18 at 06:41

1 Answers1

2

The 3 layer (anti pattern?) is a red herring here, you're essentially talking a dependency injection. pattern. These become difficult to manage manually. I'd suggest you implement a DI framework like Simple Injector or Unity.

I am trying to use interfaces as a contracts for some of my classes.

Why some of your classes? If your going to implement dependency injection then implement it on all classes.

My current issue is that i see some of the methods are common between BAL and DAL objects like: Add, Remove, GetAll therefore i decided to create interfaces to implement such thing

Here's your first mistake. You've decomposed based on functionality, not responsibility. Just because something has a similar method signature does not mean they should be related. A Customer business object has a very different responsibility to a Customer data object. Remember favour composition over inheritance.

however when using from BAL classes i need to have it like void Add(Employee) but in DAL void Add(string name);

This just highlights the above, you've made the decision that because the methods are called "Add" their the same, their obviously not.


I would say you should implement an interface for each object, dont' try and relate unrelated object, then configure this using a DI framework, then inject them. Try not to blur your lines and keep your seperations clear. Remember you want high cohesion and low coupling.


To give some examples I'd forget about your IRepositoryBal and the generics altogether and just simplify the whole thing:

//your going to struggle to do DI with internal classes, make them public
public class EmployeeBal : IEmployeeBal
{
   //
} 

public interface IEmployeeBal
{
    void Add(Employee entity);
    void Delete(Employee entity);
    IEnumerable<Employee> GetAll();
    Department Department {get; set;}
}

public class StickTogether
{
    private readonly IEmployeeBal _employee;
    private readonly IDepartmentBal _department;

    public StickTogether(IEmployeeBal  employee, IDepartmentBal  department)
    {
        _employee = employee;
        _department = department;
    }

    public void Create()
    {
        _employee.Add(new Employee());
        _department.Add(new Department());
        _employee.Department = _department; //not accessible which has a sense
    }
}

You then configure these in your DI framework, for example in simple Injector you would do:

Container _defaultContainer = new Container();
_defaultContainer.Register<IEmployeeBal, EmployeeBal>();
_defaultContainer.Register<IDepartmentBal, DepartmentBal>();
_defaultContainer.Register<IDepartmentDal, DepartmentDal>();
 //..etc.

you then get your parent instance (only!) thus:

IEmployeeBal entryPoint = _defaultContainer.GetInstance<IEmployeeBal>();

the DI framework does the rest and all your dependencies are decoupled.

Monolith
  • 717
  • 8
  • 24
Liam
  • 22,818
  • 25
  • 93
  • 157
  • hi Lian, thx for your comment, would it be possible to give some code based on my one to show the light in tunnel? – DinoDin2 Aug 31 '18 at 10:59
  • "Why some of your classes? If your going to implement dependency injection then implement it on all classes." +1 for this. If you're going to fail doing a dependency injection in one place, everything else falls apart and it makes all the other places that you did inject, moot. – WynDiesel Aug 31 '18 at 11:00
  • @WynDiesel agree however have issues to construct basics as descibed then i will fill out all ctors with DI. Can anyone show possible fix to current solution? – DinoDin2 Aug 31 '18 at 11:05
  • @DinoDin2 I've added an example. Basically you need to just simplify your design. – Liam Aug 31 '18 at 12:05
  • @Liam could you also show how Dal class could look like for Employee and how EmployeeBal reference to it? Morover your solution seems for each entity i need separate interface with almost same objects like Add/Delete/GetAll is there any way to make it one to avoid more like duplication? Hope you get my point. Thanks – DinoDin2 Sep 01 '18 at 06:48
  • @Liam can you anwer please buddy? – DinoDin2 Sep 02 '18 at 13:11
  • @DinoDin2 yes, my point is that you could use a different interface per class. Why do you really want to share an interface? Does this add any benefit to what your trying to do? Why is this duplication? If you want to avoid duplication I'd add a base class. There is literally no benefit that I can see for each class having the same interface, it also (as your question demonstrates) won't work. The `EmployeeBal` just implements the interface `EmployeeBal : IEmployeeBal` that's it. I really do think you over thinking this. – Liam Sep 03 '18 at 08:14
  • But the Dal is the same? `EmployeeDal : IEmployeeDal`? – Liam Sep 03 '18 at 08:56
  • I think you may be thinking that this answer is designed to re-write all your code for you. It's not. It's some general advice about design and where you have likely gone wrong. **You** need to apply what I've said to **your** design. @DinoDin2 – Liam Sep 03 '18 at 09:35
  • @Liam i think i correctly understood what you are saying. I think you want to say for Dal it could be designed very same way as Bal am i wrong in this ase as you wrote for dal we would have EmployeeDal : IEmployeeDal and for IEmployeeDal we would be having almost same members as IEmployeeBal is it right? If that's the case i have further question. Please of your confirmation at this point. – DinoDin2 Sep 03 '18 at 10:49
  • I am suggesting that you **could** do this as this is a classic DI pattern. there is no right or wrong here, design patterns depend on need, etc. I really don't think I can add anymore to this question than I already have. I'm also not really prepared to keep going though this in comments, I have my own work to be doing. If you have additional questions I'd suggest you add a new question, please make sure your not re-iterating what you've already added. – Liam Sep 03 '18 at 10:58