I have just started to look into DDD, and is trying to look into some scenarios.
I have a Product (Entity) with a ProductName (Value Object) and a ProductPrice (Value Object). The Product Price then have an amount (decimal) and a Currency.
My issue is regarding the Currency. First I designed this as a Value Object, but it should be possible to add new Currencies to the system, and it should also be possible to list them in some kind of GUI. In other words it seems like I need a repository for Currencies. In my mind this means that Currency should be designed as an Entity.
But, now I have a Value Object (Product Price) referencing an entity (Currency). How should this be handled? My guess (I am not sure) is that I remove the reference to the currency entity inside the Product Price, and instead adds the Id of the Currency (USD, EUR etc). The Currency then becomes its own aggregate.
Is this a valid and preferred design in DDD, or should this be done in some other way?
In the original DDD book, Evans did discuss the possibility of having values that can reference entities. (Chapter 5: "VALUE OBJECTS can even reference ENTITIES")
I think everybody, by and large, has abandoned that practice. Immutability is too powerful an idea. Values will normally only reference other values. Instead of referencing a entity, we include the entity identifier.
So the usual solution would be that you model the currency code as a value, and store (copies of) that value in your Price value.
The Currency then becomes its own aggregate.
I would not expect this to happen. How does a currency change over time?
What I think you will find is that currency is fairly static: the thing that changes over time is the CurrencyExchange -- which currencies are currently listed? what is the exchange rate today? What was the exchange rate two years ago? Which political units prefer this currency as of Thursday?
Currencies are closer in nature to units of measure: feet, inches, meters, pounds, liters seconds. Meters are a unit of measure in the dimension of length; currency is a unit of measure in the dimension of "money".
how do you handle that new currencies can be added to the system, and how can you select between currencies in the GUI?
There are two possible answers to that.
If your domain is the authority for which currencies are active in the system, then the currency registry/currency exchange should be a first class entity in your domain model, and manages the process of change to the listed currencies.
If your domain is not the authority, then you just cache a copy of the information you get from the authority. Caches are typically CRUD (PUT, GET, DELETE, maybe PATCH).
Related
Suppose I have a User entity. And this entity must have a Country field.
As a rule, Country is a Value Object.
And here it's kind of okay, and there's no problem.
But I got a ticket, which says that now on Frontend, Country must be filled in from the list of available Country (also I need to expand this list in the future)
This would be an easy task if Country was originally an entity, but I have it as a Value Object.
What to do in this case? Redefine Country as an entity, or is there another way?
Even when you maintain Countries as entities, you can store them as part of the User entity as a Value Object. The fundamental nature of a country object is such that its value is its identity, making it a good candidate for a Value object.
But IMHO, the list of Countries can be preserved as a static list because the list is finite.
I don't know what it means for your app to add a country to the list, but I am assuming that it is not as trivial as a CRUD op. If the list is rarely updated, you can maintain the list of available countries as a static list in code that is updated when necessary.
If the requirement is to often switch a country from available to not-available and vice-versa, you can store them as CRUD entities but use them as Value Objects in User.
I'm creating an iOS app which allows you to find the quickest route from one city to another. To make things easier for the user, you can filter down based on a city's continent or country too (so Europe would show Paris, London and Berlin, whereas France would only show Paris). I currently have all my objects stored in various arrays, with the City object pointing to the Country object, and the Country object pointing to the Continent object. See my diagram below for a visual representation:
I feel that this is really ineffective when it comes to filtering the data out. I want a data structure that will allow me to filter the cities out quickly. I am happy to use my 3 arrays that I currently have, but I really feel that this isn't efficient enough, and I am struggling to find a solution online. Thanks in advance.
You are trying to set up a network type database. Instead, try using a relational type database. One table of cities with extra columns for country. Then another table of countries
Suppose, I have 1000 sellers (S1.....S1000) of Apparels listed on my site. Since all the sellers are paying some amount to me, I am giving them equal weight-age, and the results are shown based on relevancy.
Now, I am planning to start with premium service, where I am thinking to list one supplier on top for each keywords in search results. Let say, S1 has been given premium search for keywords 'Jeans', so if a user searches 'jeans', I first wants to display this supplier on the top, then display other supplier based on relevancy. Plus, this premium service is for only for one month. So, another supplier say S2 can avail this service in next month and so on.
Is there any plugin, wherein I can store which supplier should be shown for which keyword. I am even OK with making 2 queries to meet the desire results.
Please suggest
I think the Query Elevation Component is your friend, you can configure which documents (and hence which suppliers) come first for any given query, see
https://wiki.apache.org/solr/QueryElevationComponent
If that's too much work, you could also add a new boolean field in your documents, indicating whether the document is to be promoted or not, and in the query, sort by this field first (so promoted documents come on top), and by score next (so most relevant documents come right after the promoted ones).
You can maybe also use the reRanking Componant :
https://cwiki.apache.org/confluence/display/solr/Query+Re-Ranking
With using a query like this :
q=jean&rq={!rerank reRankQuery=$rqq reRankDocs=1000 reRankWeight=3}&rqq=(brand:S1)
The top 1000 of results from query jean will be re-ranking thanks to the boost (of 3) add to the documents which contain the field brand with the value S1.
It can be useful, but in your case I think the QueryElevationComponent is the best.
Be careful, reRanking is only available since version 4.9.
I'm writing a monthly expenditure application where you add 'expenditures' to a month, these expenditures contain a description of what the expenditure is and the amount. For example you may have April 2015, and within that you have as expenditure items such as:
New tires for car $200
Utility bills $350
etc...
I've written the following, thus allowing you to add items to the month
class ExpenditureMonth
{
public function addExpenditureItem(String description, Money amount)
{
items.add(new ExpenditureItem(this, description, amount));
}
}
Therefore the object creation of ExpenditureItem happens within ExpenditureMonth. An expenditure month can contain many items.
When the account holder has paid for an item, it needs to be marked as paid.
How would I set an item as paid?
My only thinking is set an identifier for an ExpenditureItem and pass this instance to the addExpenditureItem method but this doesn't seem right to me?!
I had a similar question before (please read the answers).
In DDD, the parent or the aggregate root changes depending on the bounded context. So in your case, this is your context:
When the account holder has paid for an item, it needs to be marked as paid.
For that particular context, the expenditure item is now the aggregate root, and now it requires ID to be identified on its own. Setting up an ID or a GUID is the generally accepted solution, I don't think it is reliable to uniquely identify an object without a proper key.
However, if the case is "the account holder paid for all his monthly unpaid expenditures (or all unpaid expenditures)", then for that context the aggregate root is your MonthlyExpenditure.
I'm starting to learn and practice some CoreData, with no programming experience.
After searching in Web, looking for Apple samples and reading some books, I´m still stucked in one point.
I have two entities (Expenses and Month) with reciprocal relationships called "monthsOfExpense" and "expensesOfmonth" and I'm showing in a tableView the expenses of a single month.
My problem is to insert new expenses and save them: I've a view to insert new expenses where the user can insert the name of Expense, the value and the months that expense is valid (associated with the monthsOfExpense relationship, i hope).
I'm ok saving the name and the value of Expense entity, taking the string and NSDecimal number from the textFields.
My problem is how to associate that expense to a particular or several months? How can I save a textField.text as a relationship, indicating to what month an Expense belongs?
I'm starting with a textField where the user can insert a month, assuming that an Expense is valid for one month only (for learning purposes and simplification).
My idea is to allow the user to select several months (using maybe another tableView with selectable months) and association of an Expense to different months.
I know that a relationship comes as a NSSet, but I'm not being competent to save the attributes and the relationship from a View, at the same time.
Hope was cleared and many thanks in advance for trying to help.
OK. In Core data, you define your "Expense" entity, create a relationship to "Month" entity. Now create class files for these 2 entities. Then you use it by
Expense *expense1 = [NSEntityDescription insertNewObjectForEntityName:#"Expense" ....
Month *month1 = [context executeFetchRequest:......];
expense1.month = month1;
...
[context save];
In your situation, you can predefine 12 "Month" objects, giving the month name as the text property.
Then you can lookup these month objects using NSFetchRequest. Add the relevant month objects to your expense using
[expense addMonthObject:month]
Then save your managed object context.
You message the managed object for its mutableSetValueForKey:RelationshipKey,
then you add the to-many managed objects to that set. CoreData completes the other half of the relationship data.