Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top