1

As per domain model pattern we must have behavior also to the domain entities. I am using entity framework for the data access. I have extracted all the entities and moved to the domain layer as partial classes. Now I have another set of partial classes in the domain layer with behavior talking to repositories. The problem is repositories also referring the entities in Domain Model leading to circular references.

Can anyone provide the design solution for this?

Brainchild
  • 1,814
  • 5
  • 27
  • 52

2 Answers2

1

It's difficult to talk in abstract terms, so here's an example that might help. Imagine we have a service that lets Cars take trips. During this trip, Cars can run out of gas and need to change oil.

class Car {
    private GasTank gasTank;
    private OilPan oilPan;

    double MPG = 25.0;

    void drive( int distance ) {
        gasTank.consume( distance / MPG );
        oilPan.dirty( distance / OilDirtyRate ); // Making up a term here...but Oil gets dirty
    }

    void fillUp() {
        gasTank.fillUp();
    }

    void changeOil() {
        oilPan.empty();
        oilPan.add( new Oil() );
    }
}

// These are value objects, there's no identity here
class GasTank { }  // Imagine above methods defined
class OilPan { } // more methods

class CarRepository {
    Car findByVIN( String vin ) {
        // Search Car collection or database
        return car;
    }
    boolean register( Car car ) {
        carDao.insert( car.toDTO() );
    }
    boolean update( Car car ) {
        // write to persistence, etc.
    }
}

class TripService {
    private CarRepository carRepo;

    void takeTrip( String carVin, int milesToGo ) {
        Car car = carRepo.findByVIN( carVin );
        // calculate distance
        while ( milesToGo > 0 ) {
            car.drive( 200 );
            milesToGo -= 200;
            if ( car.isOutOfGas() ) {
                car.fillUp();
            }
            if ( car.needsOilChange() ) {
                car.changeOil();
            }
        }
        carRepo.update( car );
    }
}

I apologize for using yet another car example (and Java, since you're speaking C#), but you can see that Car still has logic, but the TripService can manipulate the Car as a whole. The Car is responsible for dealing with it's internal logic, such as consuming gas and dirtying the oil. Maybe drive returns the distance actually covered, if there isn't enough gas in the tank. Maybe it throws an Exception, if it isn't a normal occurrence. The drive method could also check if the car is started, has oil, has gas, and seat beats are buckled. Starting the car could consume gas at a different rate. You can see that the TripService (the 'application') talks to CarRepository and manipulates Car, but Car knows nothing about CarRepository, yet still has logic.

Handling out of gas and oil changes may not be the resposibility of a TripService in real life, but in an application that simulated car wear-and-tear, it might assume those responsibilities.

To step back to the abstract terms, your services interact with repositories and factories to obtain domain objects. Then they orchestrate the interactions between domain objects where needed. After all, something has to tell your domain objects what to do. That's where services come into play. The domain objects know nothing about repositories, since they're persistence ignorant. Knowing how itself is persisted doesn't affect the business logic, so you don't handle that within the domain objects. They just handle business logic and maintaining invariants. Repositories have to know about domain objects, since they're persisting and retrieving them.

Steven Hood
  • 678
  • 5
  • 18
  • So. There will be set of services in the Domain Model which will take care for filling the domain entities either from the Repositories or from the layers above the domain model – Brainchild Apr 03 '13 at 07:07
  • Yes, I think that's accurate. I would clarify your service and repository interaction. The service asks the repository for a domain object. Once it's returned from the repository, it's essentially ready to use in your domain layer. – Steven Hood Apr 03 '13 at 16:15
0

Move the partial classes in the domain layer with behaviour talking to repositories into appropriate services.

Your model isn't supposed to know anything about the repositories. Your repositories take the model and persist it to your database.

You then have a layer on top of model, be it WCF service or controller in ASP.NET MVC or Main method in a console app that sits at the top and organises the domain model interactions and then persists to database through the repository.

Your model is not the place to put all of your application.

Jack Hughes
  • 5,514
  • 4
  • 27
  • 32
  • Your solution contradicting the principles of Domain model pattern http://martinfowler.com/eaaCatalog/domainModel.html – Brainchild Apr 02 '13 at 13:20
  • Care to explain how you think it contradicts the Domain model pattern? Because I can't see anything that does. – Jack Hughes Apr 02 '13 at 13:39
  • If I move behavior classes to services my entities in the domain layer will become like DTOs. Please refer the link in my previous comment for more information about Domain model pattern – Brainchild Apr 02 '13 at 13:44
  • If your domain classes need to talk to your repository then they aren't domain classes. Nowhere does Martin Fowler say that all code must go into the domain model. You need something to control interaction with the domain model and then persist the changes. See here for more info http://stackoverflow.com/questions/2268699/domain-driven-design-domain-service-application-service – Jack Hughes Apr 02 '13 at 14:41
  • I am curious to know what short of behavior a domain model will have without data from some repository. Lets say if I expose some Infrastructure service for the Data and I directly consume the same from Application Services, I am not seeing the real advantage of introducing Domain Layer and Domain Driven Design – Brainchild Apr 02 '13 at 16:24
  • This text is from the book N-Layered_Domain_Oriented_Architecture_Guide_with_ .NET_4.0 "If the aggregate‟s objects need to be persisted in the database, then they should only be accessed through the root entity. The secondary objects must be obtained through associations. This implies that only the root entities of aggregates may have associated REPOSITORIES. The same happens at a higher level with the SERVICES. We can have SERVICES directly related to the AGGREGATE root entity, but never directly related to a secondary object of an aggregate." – Brainchild Apr 02 '13 at 17:40
  • @Brainchild, see my answer for an example that I think helps clarify how logic can get split between services and domain objects. – Steven Hood Apr 03 '13 at 06:21