how to implement services and repositories on onion architecture?
Asked Answered
E

3

7

I've been studying onion architecture for a couple of days. I understand that dependencies should always go toward the center and how to use dependency injection to accomplish this. But I have a couple of questions I still couldn't figure out.

  1. Can a model (or entity) reference a repository interface or a service interface?

    Eg: an Order entity has a DeliveryCity relationship established through Oder.DeliveryZip property, which is not a foreign key, but is unique. To get the City for a zip, I must call ICityRepository.FindByZip(zip)

    I have the following code in my model

    class Order
    { 
        . . .
    
        [Inject]
        public ICityRepository CityRepository { get; set; }
    
        private City _dCity;
    
        public City DeliveryCity {
            get {
                if (_dCity == null)
                    _dCity = this.CityRepository.FindByZip(this.DeliveryZip);
    
                return _dCity;
            }
        }
        . . .
    }
    
  2. What would be the problems of the above code? Should it use a domain service instead?

  3. Should the domain services implementations be defined inside the core or at the infrastructure layer?

Ewald answered 4/5, 2012 at 3:47 Comment(0)
R
6

This is where Factories fit into the domain. An OrderFactory can take dependencies, such as a dependency on the IOrderRepository as well as a dependency on ICityRepository. When the factory is used to create (or reconstitute) an Order entity, the factory can lookup the City and set the Order property accordingly. Or, as herzmeister suggests, set it using Lazy so the lookup is only performed if/when needed.

Reseat answered 14/5, 2012 at 13:4 Comment(3)
It makes perfect sense! I'm asking myself "how could I miss that?"! Thanks!Ewald
This is a mistake. DDD factory are not responsible for reconstitution. Reconsitution is the middle life of an object, Factory is only concerned with the beginning of life. Please see this answer: https://mcmap.net/q/1480689/-domain-driven-design-issue-regarding-repositoryOslo
I disagree. Factories are used to create instances of an object. They can be at the beginning of an object's life cycle or used for reconstitution. They may be the same class with two methods or two different classes. Either way, I do agree that there is a difference in how the factory behaves in each case. I usually have the reconstituting factory as a dependency of the repository which delegates to the factory to create and reconstitute the new instance with the data retrieved from the data store. For more information, see Evans pg 145: "Reconstituting Stored Objects"Reseat
O
5

What would be the problems of the above code? Should it use a domain service instead?

Two things to consider here:

  1. ICityRepository is not a real dependency for Order, in other words Order does not need it for its other methods. Real dependency is something that the object can not work without. So you may want to consider passing it as a parameter to the method like 'GetDeliveryCity' (see this for details).

  2. Finding city by zip code does not seem like a responsibility of the order. For Order to be cohesive it has to deal with order-related functionality only. You may want to take this functionality out of the order class.

Should the domain services implementations be defined inside the core or at the infrastructure layer?

Inside the core if this is truly domain service (not application service).

Oslo answered 4/5, 2012 at 16:45 Comment(0)
I
0
  1. How about

    private Lazy<City> _dCityLazy;
    
    public City DeliveryCity {
        get {
            return _dCityLazy.Value;
        }
    }
    

    where you'd inject the Lazy<City> by some mechanism?

  2. You'd decide flexibly by injection from outside then in this example.

  3. I'd say it really depends what a particular domain service does and where it is used.

Impearl answered 4/5, 2012 at 17:8 Comment(2)
Injecting the city through an IoC would lead to adding business rules to the dependancy injector, which is really bad. I'm not sure that's what you proposed thouhg.Ewald
of course business rules in the dependency injector is really bad, but it doesn't have to be that way. There are many other possibilities. There can be a domain service in between. Or, simple id look-ups are obviously the job of a repository, carrying the actual method from where the delegate for the Lazy<T> will be referenced. Generally, I just like to keep my entities simple, i.e. without any knowledge of the structure of the actual persistence, i.e. without any references to services or repositories.Impearl

© 2022 - 2024 — McMap. All rights reserved.