8

I want to build a web application with 3-tier architecture in ASP.NET. But I am getting a problem of circular referencing.

I have 3 layer:

  1. Application layer containing UI.
  2. Business layer containing all the logic and domain classes.
  3. Data layer containing all database interaction methods.

I am using the data layer methods in business layer to perform database operations and in these methods I need to pass domain class object to data layer but it can not be done due to circular referencing.

For example I have a Person domain class containing some properties and methods. Now I want to insert that Person into database. I have a method in Person class, named as InsertPerson(). In this method body, I have to call the function of Data layer to insert into database. But I am not able to pass the whole person object into data layer method as data layer reference is added to business layer and vice-versa is not possible.

So how can I avoid this problem? Please suggest.

Maximin
  • 1,655
  • 1
  • 14
  • 32
atul
  • 561
  • 4
  • 12
  • How I've seen it done is 1. there is a base class of all business objects, that both the business and data layer know about. It knows its table and is associated with a row. 2. to save, the data layer just needs to take its row, examine its scheme, construct the query to save it and save it in that table. 3. to load, the data layer is passed a type that subclasses businessobject to make, and reflectively uses the type's constructor on the row it gets from the table. – Patashu Apr 02 '13 at 05:56
  • I added an edit to my answer to clearer describe what I meant. – Piotr Perak Apr 02 '13 at 21:28

4 Answers4

6

Is it possible to split the domain objects from the business logic for manipulating them? So you have classes describing the data, containing relatively primitive operations, and then your business layer is more actions on the data - often using several different classes in one action.

You then end up having four assemblies:

  UI              /
  Business logic  | Domain classes
  Data layer      \

So all three layers use the domain classes as common terminology, effectively.

I've seen this work pretty well - it does mean that your domain classes typically become slightly "dumb", although they can still contain relevant logic around some validation etc for aspects which are independent of other classes.

Of course, there are plenty of alternative approaches :)

Ofer Zelig
  • 17,068
  • 9
  • 59
  • 93
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • how does SavePerson method look like in data access layer in this solution. – Piotr Perak Apr 02 '13 at 06:16
  • @Peri: It's hard to answer that without more information - but I'd expect the data layer to contain no business logic - just know where and how the entities were stored. Exactly what that means will depend on a lot of other context. (I've been working on pretty proprietary solutions for too long to comment in general on this, unfortunately.) – Jon Skeet Apr 02 '13 at 06:23
  • I should be clearer. I wanted to ask if DataAccess.SavePerson receives Person as parameter or firstname, lastname. I don't understand how are references between assemblies organized. – Piotr Perak Apr 02 '13 at 06:58
  • @Peri: Person, IMO. I prefer to keep objects organized in meaningful ways for as long as possible. – Jon Skeet Apr 02 '13 at 07:06
  • @JonSkeet: Thanks for your quick reply. I read somewhere that in 3-tier architecture, we should keep business logic and domain classes in same layer. The solution that you have provided is pretty good and I also thought about this. But I don't what is the best way to get rid off this circular referencing issue as I told. You have mentioned that there are more approaches. Can you please tell me other one? Or Should I use the approach you have told in your answer? Please suggest. – atul Apr 02 '13 at 11:47
  • 1
    @atul: Well there's the DDD approach given by Nagg, for one. Basically *any* description is going to look a little different by the time each person has interpreted it. I wouldn't go by "I read somewhere" - I would go by descriptions of things that clearly work. If you want to follow an approach which keeps the domain classes in the business logic layer, that's fine - but if that's from following a description from a book, you should turn to that book to find out what they do about the storage layer (which definitely shouldn't have a reference "up"). – Jon Skeet Apr 02 '13 at 11:56
  • 1
    @JohnSkeet: What do you mean when you say storage layer should not have reference up? – Piotr Perak Apr 02 '13 at 18:58
  • 1
    @Peri: Traditionally layered architectures only allow "higher" layers to know about "lower" layers - so a storage layer (bottom) shouldn't know about a business layer (middle). – Jon Skeet Apr 02 '13 at 19:02
  • 1
    But do you think that is good? This leads to problems as in question. DataAccess layer having reference to BLL is good way to organise it. BLL should have no references only define what it want's to work with. For good discussion on this you can look at Mark Seeman's Dependency Injection in .NET - Chapter 2. Author talks exactly about scenario from this question. Also earlier I asked what would SavePerson receive as parameter and you said Person. If data access layer doesn't have reference to domain (up) then it is impossible to pass Person to this layer. I don't understand. – Piotr Perak Apr 02 '13 at 19:24
  • 1
    @JonSkeet: Thanks. Appreciate your suggestions. If I separates the Domain Classes from Business Logic and make it as a separate common layer, then I will not be able to create methods like Set and Get data in domain classes and have to create these methods in Business Layer. So, in 3-tier architecture, is it necessary to create Set and Get methods in domain classes? Or I can create them in business layer also? – atul Apr 03 '13 at 11:20
  • @JonSkeet: Apart from this, if I create a single project and all these layers are maintained as namespaces, then I think there will not be any problem of circular reference. Is this a correct approach? and Still this will be called as 3-tier architecture? – atul Apr 03 '13 at 11:39
  • 1
    @atul: It doesn't end up being a layer - it's to the side of the other layers. It's not really clear what you mean by the get and set methods, to be honest... Yes, if you have a single DLL you won't have reference issues, but that just means you're letting yourself mess up your layering, by allowing a lower layer (storage) to refer to a higher layer (business). – Jon Skeet Apr 03 '13 at 11:51
  • @JonSkeet: By Get and Set methods, I meant the methods which are used to interact with data layer. For example, in Person domain class, there are two methods GetPerson and SetPerson which further call the methods of Data layer to Get and Set Person's data in database. – atul Apr 04 '13 at 07:00
  • @atul: I'd personally try to avoid that to start with. I'd probably make the domain classes pretty much pure data. Aside from anything else, that makes them much easier to use in tests. – Jon Skeet Apr 04 '13 at 07:02
  • @JonSkeet: Thanks Jon for your valuable suggestions. It will be very helpful for me in building my application with a better approach. It will be good to hear you again. :) – atul Apr 04 '13 at 07:29
4

Your business logic dll should not have reference to the data access layer. Data access layer should have reference to your business logic dll. Business logic code should define interfaces it wants to talk with in order to access database (or other external to business logic stuff) and other dlls should implement them to provide services for business logic layer.

This is the Dependency Inversion Principle. It says that high level modules should not depend on low level ones. Here business logic is the high level module. Data access dll is just implementation detail from Business logic dll perspective.

To show example

BLL:

public interface IPersonRepository
{
    void SavePerson(Person p);
}
public class PersonServices
{
    PersonServices(IPersonRepository repo)
    {
      //
    }
    public void FirePerson(Person toFire)
    {
        toFire.FireHim();
        repo.SavePerson(toFire);
    }
}

DAL:

public class PersonRepository : IPersonRepository
{
   // ...
}
UI:
var repo = new PersonRepository();
var ps = new PersonService(repo);   // wire by hand or use container

ps.FirePerson(somePerson);

References:

UI -> BLL
   -> DAL

DAL -> BLL

BLL -> nothing!
Piotr Perak
  • 10,718
  • 9
  • 49
  • 86
1

You'd better use classic DDD: Domain (business logic) should not have any reference to DAL (Infrastructure for persistence) it just declares interfaces that infrastructure has to implement (repositories) than in Application layer you write app services that use domain and the presentation layer uses only application layer (or distributed services if its about distributed app):

enter image description here

Good example of (D)DDD: http://microsoftnlayerapp.codeplex.com/

EgorBo
  • 6,120
  • 3
  • 35
  • 40
-1

If you use 3-tiers architecture in your application, you are unable to pass object to data access layer. the ojects can be used in business layer only. The best architecture is domain module if you want to use object in data access layer.

ice-cream
  • 21
  • 2