Loading a Value object in List or DropdownList, DDD
Asked Answered
L

4

8

I need to clarify something.

Have Person Aggreagate , 2 VOs (Country, StateProvince).

I want to load all country in my presentation layer (i am using mvc)

Evan says you only use repository (IPersonRepository) to work with root entity (it should always return just a reference to the Aggregate Root)

   public interface IPersonRepository()
   {
     void savePerson(Person p);
     void removePerson(Person p);
     Ilist<Person> getPerson();
   }

what i usually do to solve this :

Add in IPersonRepository this method

IList<Country> LookupCountrysOfPerson();

In Infra layer implement the Domain interfaces like this:

public IList<Person> LookupCountrysOfPerson()
{
    return Session.CreateQuery("from Countrys").List<Person>());
}

My partner says im wrong.

Sometimes you have to sacrifice your domain model in order to accomplish some task

What is the best way to do this?

with code please! :)

Lys answered 29/3, 2011 at 20:4 Comment(0)
D
5

Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."

I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.

Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.

Danner answered 30/3, 2011 at 6:21 Comment(7)
But sometimes we need to bind list of vo's in dropdown list. In that case what should we do, Is it ok to have a looup function in repository which returns list of Vo's, so that we can bind it in ddl. Do we create country as entity in the Person aggregate or as separate aggregate in which Country is root aggregate.Southeastward
When you delete an aggregate you should delete everything. If you were to delete a person you would also delete any Country object. Is that actually what you want to do? If not yes I would probably just move this data out as a standalone object or a small aggregate of Country,State,City etc and then you can query that directly. Aggregates exist to create a single unit of work for db transactions, and to simplify the model. Objects like Country do not require a lot of understanding so unless they are an integral part of a transaction, adding them to an aggregate serves no purpose.Danner
@sisyphus, Please see my answer and correct me if i am wrong.Southeastward
"consider creating a single lookup service that provides query access for a group of similar objects of this nature", Can you elaborate on this more and what if tomorrow i want to add new country in the list of countries. i want to save all this in database.Southeastward
Often objects are needed but contribute little "domain knowledge". If State is only for addresses it is not a major feature. A lookup service can be called by the client app to populate various types of dropdowns instead of a regular single object repository. Think of a multiple object repository if the service part is confusing. Aggregate rules can also often be ignored for these simple objects. I might have a Country aggregate with Country/State/City but I might have a single "Address Repository" that returns a list of Countries, States, Cities, Zipcodes, whatever you needed.Danner
DDD is a philosophy, with some rules and guidelines, that is useful for developing complex applications. It is not a protocol or standard. There is no one answer. State might be used only in addresses. In another app, say legal app, State might be a core object that encapsulates behaviors of a "jurisdiction", not just a part of an address. DDD/aggregates are for the second case. Developers could add a new Country from a script. If a user can add a new Country save it however you save any other object. You'll never get 100% right, save it however you think and refactor as you need to.Danner
@sisyphus' advice is sound. location is a common entity in many systems. both country and stateprovince would be a part of this location aggregate not the person aggregate. just because a person has a location doesnt make location part of the person aggregate. locations clearly fail the delete test for person.Bernardinebernardo
J
8

I would say it's unlikely that you need country to be an entity. I suspect that country is nothing more than reference data, much like a person's title would be. Is there any behavior associated to country in your domain? I suspect it's just what's printed onto letters/envelops.

This question is somewhat similar to this one which I answered a while back:

Simple aggregate root and repository question

My suggestion is that you implement a Lookup service that your client can make use of and which is cached. Ignore the rules of DDD and anything to do with aggregates or repositories for this. As someone else has mentioned, this is where CQRS's ideology comes into play; the client shouldn't have to go through the domain in order to get data. The domain is purely transactional, not designed for queries.

This article explains how to build a generic lookup service for reference data for things that typically fill dropdowns in the UI (i.e. Title, Country etc)

http://wtfperminute.blogspot.com/2011/02/working-with-reference-data-lookups.html

Jews answered 30/3, 2011 at 14:36 Comment(12)
Can you elaborate more on look up service, If tomorrow i want to add another country in list, How will i do that ?. Do i add manually in database .Southeastward
I work in health care where this approach is often a requirement. Do a web search on "EAV" + "schema" - it is essentially the same thing. I would never advise this technique as anything but a last resort. Relational data is designed as a row being a set of related data with attributes defining the columns. As soon as you pivot that concept into a row based attribute model you begin working against the database paradigm and open up a world of possible problems.Danner
@Kamal - Easy, you build a UI screen that allows users to configure their lookup items as they please - it's configurable data. The app that I work on is designed for multiple clients, so each client can choose their own list of countries. Typically a default list is installed when the app is installed - which the clients can then configure.Jews
@Danner - I'm not entirely sure what your point is. I'm only suggesting this technique for configurable reference data - which I consider 'Country' to be in this instance. I also happen to work in healthcare; we don't apply EAV to domain entities - just this configurable data. Unless there is domain logic involving Country - why would it be an entity?Jews
@Danner - Just to clarify something - I'm not suggesting you add an attribute to Person to store his/her country. Person would have a property to a Country value object. Just that the persistence and queries for Country is done so via a LookupService, not by methods added to the PersonRepository.Jews
@DavidMaster84 - If Person has a Country VO as property, then if i delete person then , say country will also be get deleted, This is according to @Sisyphus. I understood that i can have look up service, as application service in my project. But to add new country do i have add method too in that service.Southeastward
@Kamal - That doesn't make much sense. If Person gets deleted then Person's reference to a particular country gets deleted. Not the actual country itself. In database terms, Person would have a country ID. Yes, the lookup service would have methods to add, edit and delete items. Essentially it's a repository, but by calling it a LookupService means Repository is a term that's only used for the persistence of aggregates, whilst LookupService provides the UI direct access to this static/configurable simple data types.Jews
"If Person gets deleted then Person's reference to a particular country gets deleted." This is what i was thinking and i am 101% agree. I was confused with @Sysphius answer.Southeastward
This is my point. This is one way to check to see if your aggregates make sense. IF Country is part of an aggregate then that aggregate is created and deleted as a single unit. If you delete a Person, and Country was a member of the Person aggregate, you also delete the Country. You probably really do not want to do that, so you know by that Country should NOT be part of the Person aggregate. Saying a Person's reference to a Country is deleted but not the Country itself is equivalent to saying that Country is not part of the Person aggregate.Danner
@david look up service will be app service or domain serviceSoutheastward
@Sysphius, If Country is vo and part of Person , then changing in one person's country does not effect other Person's country. But if Country is entity in Person aggregate, then changing the name or deleting a country will effect on all person's. In my case country is VO.Southeastward
I understand that. But your original question was about getting Country objects - for loading into a list vs. for a specific Person etc. That is usually an aggregate issue, not an entity vs VO issue. If Country is part of Person aggregate, you have problems. If Country is it's own aggregate not a member of a Person everything is simple. You can get a list of Country objects for the UI etc from a repository or lookup service, and you can get the Country objects associated with a Person object by traversal. That is true for both entity and VO.Danner
D
5

Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."

I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.

Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.

Danner answered 30/3, 2011 at 6:21 Comment(7)
But sometimes we need to bind list of vo's in dropdown list. In that case what should we do, Is it ok to have a looup function in repository which returns list of Vo's, so that we can bind it in ddl. Do we create country as entity in the Person aggregate or as separate aggregate in which Country is root aggregate.Southeastward
When you delete an aggregate you should delete everything. If you were to delete a person you would also delete any Country object. Is that actually what you want to do? If not yes I would probably just move this data out as a standalone object or a small aggregate of Country,State,City etc and then you can query that directly. Aggregates exist to create a single unit of work for db transactions, and to simplify the model. Objects like Country do not require a lot of understanding so unless they are an integral part of a transaction, adding them to an aggregate serves no purpose.Danner
@sisyphus, Please see my answer and correct me if i am wrong.Southeastward
"consider creating a single lookup service that provides query access for a group of similar objects of this nature", Can you elaborate on this more and what if tomorrow i want to add new country in the list of countries. i want to save all this in database.Southeastward
Often objects are needed but contribute little "domain knowledge". If State is only for addresses it is not a major feature. A lookup service can be called by the client app to populate various types of dropdowns instead of a regular single object repository. Think of a multiple object repository if the service part is confusing. Aggregate rules can also often be ignored for these simple objects. I might have a Country aggregate with Country/State/City but I might have a single "Address Repository" that returns a list of Countries, States, Cities, Zipcodes, whatever you needed.Danner
DDD is a philosophy, with some rules and guidelines, that is useful for developing complex applications. It is not a protocol or standard. There is no one answer. State might be used only in addresses. In another app, say legal app, State might be a core object that encapsulates behaviors of a "jurisdiction", not just a part of an address. DDD/aggregates are for the second case. Developers could add a new Country from a script. If a user can add a new Country save it however you save any other object. You'll never get 100% right, save it however you think and refactor as you need to.Danner
@sisyphus' advice is sound. location is a common entity in many systems. both country and stateprovince would be a part of this location aggregate not the person aggregate. just because a person has a location doesnt make location part of the person aggregate. locations clearly fail the delete test for person.Bernardinebernardo
M
2

If in your domain country is actually a VO (you don't want to maintain a thread of identity in the country name was changed etc.) which is the most common scenario, I would add a specialized class in the data access layer to return a list of all countries as VOs. I would also add caching (2nd level cache in NHibernate) to the country entity and list all countries query so that I don't have to hit the DB each time.

Actually, this is where CQRS really shines. CQRS acknowledges that you don't have to go through the domain layer in order to get some data for presentation purposes. In CQRS you just grab some data.

Margarite answered 30/3, 2011 at 13:32 Comment(2)
what if i want to add new country in database later or if i want to get all corresponding Stateprovinces of a country. Returning a list of countries is fine but if i want to add new country in database.Southeastward
This is essentially what I'm suggesting too, apart from I would create a generic lookup solution so you don't have to create a specialised class and a seperate DB table for these types of objects (country, title, religion etc) as they all share the same structure - ID, Description, Code (optional).Jews
J
1

It sounds like countries are not in fact value objects here; they have distinct identities and are important for business purposes outside of your Person objects. They should become entities, and be treated in the fashion appropriate to them.

Think of it this way: let's say some volatile country had their current dictator overthrown and got a name change. The Person object's reference to a Country should still be valid, because the Country is not defined by its attributes (i.e. the string denoting its name), but by its identity.

Juxtapose answered 29/3, 2011 at 20:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.