Mapping lookup table to class - nhibernate

I have a reference/lookup table whose main purpose is to provide the user with a list of existing options. The user will also have the ability to enter new items into the list. How would you map this in NHibernate?
For example, say I have an Address class with a City field. The database has an Address table and a City lookup table. (I can define the relationships however I want at this point.) When editing the address:
The user can select any available City, or can enter a new City.
A new city entered must be added to the lookup table.
Editing an Address instance's city should either change the reference - if the edited city also exists in the DB - or create a new City entry by that name and refer to it. (If I edit "Chicago" to "New York", I don't want all addresses in Chicago to change to New York; just the one I'm looking at.)
I've been scouring NHib docs, and I'm not at all sure what approach I should take.
EDIT:
Part of my issue stems from the fact that I'm trying to avoid creating a "City" class with a single property - I'd just like Address.City to be a string in the domain model. This may be unwise, I don't know.

So you have addresses and you want a distinct list of cities. You'll either need to do the "distinct" operation in your code or in the database. Doing it in code implies a City class mapped onto your City table - I can't see how you can avoid it.
If the "distinct" operation is done it the database, you'll need write sprocs to insert and update an Address. These sprocs would then contain the logic of "use the City if it's in the table, otherwise create a new one".
Personally I'm not in favour of sprocs if they can be avoided and so I'd recommend that you create a City class and map it with a on your Address class.

Related

How to design table or collection for storing destinations?

I have an task to store data about destinations of delivery, where companies can ship the postal parcel.
The trivial way is to create a table
CompanyShippmentPlaces
id | country | city
There are the some design issues:
What if need be delivered to towns or villages, not to cities? That means altering a table?
What if company needs to specify a part of city, townm or village?
What if the destinations have the same name?
How I plan to use this data:
When system gest a order, the order should be distributes across all companies. I must get all companies that can deliver this product.
It pushes me to use noSQL database, but I am not confident.
What do you think about that?
What if need be delivered to towns or villages, not to cities? That means altering a table?
This would be solved by the solution of jaimish11.
Peronsaly I would change the naming of "City" to "locality" (or something comparable - to generalize).
What if company needs to specify a part of city, townm or village?
I think this is solved by the address lines.
What if the destinations have the same name?
Normaly (as much that i know) each location in a country has it's own pin- or zipcode respectively if the naming doesn't match the post will use the code to identify the location. (to be sure you should ask the post in your at least in your country)
When system gest a order, the order should be distributes across all companies. I must get all companies that can deliver this product.
I would get all locations where the products are available and then get the location wich is next by the city out of the first selection. Maybe you could save the nearest location to a city in your "city table".
The issue you're describing isn't actually an issue. No matter what database you use (SQL or NoSQL) you can simply have all the address fields you need such as:
Address Line 1
Address Line 2
Landmark
City
Pincode/ Zipcode
State
Country
This way, it won't matter whether it's city, town or village.

How to force a City entity to have its name available in all locales (languages)?

I would like to design a database where the city name MUST exist in all the available locales (languages). I currently serve these locales:
en, fr, it and es.
My initial thought is to save the name inside the cities table but instead of having one name field, I'd have name-en, name-fr, name-es and name-it.
Thus, the city of London would be saved like this inside the cities table:
My second thought is that it'd be more production-appropriate to have a table of all served locales so that once we add a new locale it'd appear on the website automatically as an extra option. Thus, I made this ERD:
Which means that the many-to-many between City and Locale would generate the following table:
So far so good, but I'm not sure how to FORCE that once a new city is added it MUST has it's name available in all locales. Or is that only possible using backend code?
Note:
This is a hiring assignment, so I don't have specific business rules just to think of a smart and scalable solution.
Thanks.
In your first solution, you can use a check constraint:
alter table t add constraint check_all_names
check (name_en is not null and name_fr is not null and name_es is not null and name_it is not null);
The second is basically not possible with a well-designed data model in SQL. Why?
To insert into city_locales you need a valid city_id.
By definition, you cannot have a valid city_id until you have all locales.
Further, constraints generally need to be true as rows are inserted. You cannot insert one row into city_locales and have the constraint be true (assuming you have more than one locale).
One way around this would be to have a flag on the cities table that specifies if all locales are created. You can update the number of locales using a trigger. Or, you can use a view and calculate the flag on the fly.

Localisation of country names

As part of addresses I am storing in my SQL database country codes (e.g. US, DE,...). I then have another table (with two columns) in my database which translates the country codes to the English language names of the respective countries.
If I want to make the site multi-language, I could expand this translation table adding country names in other languages than English.
I was wondering if there is another method which does not involve modification of the database, e.g. using gettext to translate the English country names?
The typical way to handle this is to change the table structure to have three columns, instead of two:
Language
CounryCode
FullName
Whenever you query the database, you would provide the current language.
You then have to change your code to include the additional language key in any queries.
Depending on how you are going to keep track of the current language, you would also use a view or user defined function.
You don't want to use automated translation, since the name of a country like "China" could turn into the equivalent of "porcelain".

Update an entity inside an aggregate

I was reading a similar question on SO: How update an entity inside Aggregate, but I'm still not sure how a user interface should interact with entities inside an aggregate.
Let's say I have a User, with a bunch of Addresses. User is the aggregate root, while Address only exists within the aggregate.
On a web inteface, a user can edit his addresses. Basically, what happens is:
The user sees a list of addresses on its web interface
He clicks on an address, and gets redirected to this page: edit-address?user=1&address=2
On this page, he gets a form where he can modify this address.
I we decided to bypass the aggregate root, this would be straightforward:
We would directly load the Address with its Id
We would update it, then save it
Because we want to do it the DDD way, we have different solutions:
Either we ask the User to get this Address by Id:
address = user.getAddress(id);
address.setPostCode("12345");
address.setCity("New York");
em.persist(user);
The problem with this approach is, IMO, that the aggregate root still doesn't have much more control over what's done with the address. It just returns a reference to it, so that's not much different from bypassing the aggregate.
Or we tell the aggregate to update an existing address:
user.updateAddress(id, "12345", "New York");
em.persist(user);
Now the aggregate has control over what's done with this address, and can take any necessary action that goes with updating an address.
Or we treat the Address as a value object, and we don't update our Address, but rather delete it and recreate it:
user.removeAddress(id);
address = new Address();
address.setPostCode("12345");
address.setCity("New York");
user.addAddress(address);
em.persist(user);
This last solution looks elegant, but means that an Address cannot be an Entity. Then, what if it needs to be treated as an entity, for example because another business object within the aggregate has a reference to it?
I'm pretty sure I'm missing something here to correctly understand the aggregate concept and how it's used in real life examples, so please don't hesitate to give your comments!
No, you're not missing anything - in most cases the best option would be number 2 (although I'd call that method changeAddress instead of updateAdress - update seems so not-DDD) and that's regardless whether an address is an Entity or Value Object. With Ubiquitous Language you'd rather say that User changed his address, so that's exactly how you should model it - it's the changeAddress method that gets to decide whether update properties (if Address is an Entity) or assign completely new object (when it's VO).
The following sample code assumes the most common scenario - Address as VO:
public void ChangeAddress(AddressParams addressParams)
{
// here we might include some validation
address = new Address(addressParams);
// here we might include additional actions related with changing address
// for example marking user as required to confirm address before
// next billing
}
What is important in this sample, is that once Address is created, it is considered valid - there can be no invalid Address object in your aggregate. Bare in mind however, that whether you should follow this sample or not depends on your actual domain - there's no one path to follow. This one is the most common one though.
And yes, you should always perform operations on your entities by traversing through aggregate root - the reason for this was given in many answers on SO (for example in this Basic Aggregate Question).
Whether something is an entity or VO depends on the requirements and your domain. Most of the time address is just a Value Object, because there's no difference between two addresses with the same values and addresses tend to not change during their lifetime. But again, that's most of the time and depends on domain you're modeling.
Another example - for most of the domains a Money would be a Value Object - 10$ is 10$, it has no identity besides amount. However if you'd model a domain that deals with money on a level of bills, each bill would have its own identity (expressed with a unique number of some sort) thus it would be an Entity.

Doctrine optional OneToOne mapping

I'm trying to create a optional OneToOne mapping in Doctrine.
I have a table with all cities and zip codes available (this table shouldn't be changed), and I have a table with addresses and a mapped city. But sometimes I don't want to add City to my Address at the beginning (maybe later on it will). But when I don't add a City to the Address the persist on the Address gives me a Reflection Exception because there is no object like 'null' , which should be de City object.
I don't want to add an empty city every time into the database, because there should nothing be added or deleted to the city table.
Any suggestions? Or what am I missing?
class Address{
/**
* #OneToOne(targetEntity="City")
* #JoinColumn(name="city_id", referencedColumnName="id")
*/
private $city = '';
Possible solutions I considered:
Create an empty city object in the db and assign this always to newly created Address objects (might cause a lot of overhead)
Create a ManyToMany relationship with an array of cities, so there can be zero or more cities added (I can restrict the multitude of cities in my Address object) but then I need a mapping table...
Just simply add nullable=true to #JoinColumn annotation