Data Gateway Pattern and Foreign Keys - php

How are this two concepts work together ?
I have a scenario
city table
country table
city.country_id is a FK to country.id
Objective
fetch all the cities and display the country name also
My problem
the fetch method will get the cities from the table
if I need the country name I would have to do an extra search for it or an inner join
but by doing so I make extra queries when they are not necessary (display just the a city info for example)
Question
What is the right way to apply the Data Gateway Pattern in this case.

You should use a join if you need h associated country name. Simply add another method like fetchWithCountry.

Another option is to create a view of the city table that includes the CountryName. Then get your DataGateway to select using the view and save using the table. In your domain objects make the CountryName field a dumb read only field. This approach might seem like a dirty hack but it does simplfy things.

Related

Approaches for user extensible entities with a relational database (mySQL)

We have a php/mysql system with about 5 core entities. We now need to add the ability for customers to create custom fields for some of these entities on a per project basis.
They would contain a label, key, type, default value, and possible allowed values.
This is so they could add a custom date field, or a custom dropdown to the UI and save this value against the specific entity.
What is the best approach for storing this kind of data in a mySQL database? I need to store both the config for the field, and then the current value for a specific entity.
I've had a look at various options here.. https://ayende.com/blog/3498/multi-tenancy-extensible-data-model
But this is not really at a tenancy level, more a project level.
I was thinking...
A CustomFields table to hold the configuration of a field against an entity type and project id.
A CustomFieldValues table to hold the value saved against the field - a row per field ( entity_id | field_id | field_value)
Then we create relationships between the entities and these custom values when retrieving the entities.
The issue with this is that there will be as many rows in the Values table as there are custom fields - so saving a entity will result in X extra rows. On top of that, these are versioned, so once a new version is created, there will be another X rows created for that new version.
Also, you can't index the fields on name, joins would become pretty complex i think as you have to join to the configuration and the values to build the key value pair to return against the entity, and how would you select based on a custom field name, when the filed name was actually a value?
I don't want to add dynamic columns to the table, as this will affect ALL the entites in the whole system - not just the ones in the current client / project.
The other option is to store the values in a JSON column.
This could be on the entity row itself customFields or similar. This would prevent the extra rows per field, but also has issues with lack of indexing etc, and still need to join to the config table. However, you could perform queries by the property name if the key=value was stored in the JSON... WHERE entity.customFields->"$.myCustomFieldName" > 1.
Storing the filed name in the json does mean you cannot change it once created, without a lot of pain.
If anyone has any advice on approaches for this, or articles to point me at that would be much appreciated - Im sure this has been solved many times before....
JSON records: No! A thousand times no! If you do that, just wait until somebody actually uses your system for a few tens of millions of records, then asks you to search on one of your extra fields. Your support people will curse your name.
Key-value store. Probably yes. There's a very widely deployed existence proof of this design: WordPress. It has a table called wp_postmeta, containing metadata fields applying to wp_posts (blog pages and posts). It's proven successful.
You will need to do some multiple joining to use this stuff. For example, to search on height and eye-color, you'd need
SELECT p.person_id, p.first, p.last, h.value height, e.value eye_color
FROM person p
LEFT JOIN attrib h ON p.person_id = h.person_id AND h.key='eye_color'
LEFT JOIN attrib e ON p.person_id = e.person_id AND e.key='height'
WHERE e.value='green' and CAST(h.value AS INT) < 160
As the CAST in that WHERE clause shows, you'll have some struggles with data type as well.
You'll need LEFT JOIN operations in this sort of attribute lookup; ordinary inner JOIN operations will suppress rows with missing attributes, and that might not work for you.
But, if you do a good job with indexes, you'll be able to get decent performance from this approach.
The table structure envisioned in my example doesn't have your table describing each additional field, but you know how to add that. It also doesn't have explicit support for multi-project / multitenant data separation. But you can add that as well.

Multiple entries in a MySQL column in php

I am creating a mysql database with companies that cover a certain postcode. I want users to be able to type in a complete postcode (zipcode) (eg SW1 1FT) and the query return all company names etc that cover the postcode (SW1)
my first table "members" will contain "ID", "Company_Name", "Phone_Number",and possibly "Postcodes_covered"
Now I understand that listing several postcodes under the Postcodes_covered column is big no no! Can anyone offer any advise or can i just add SW1, SW2, SW3 etc to a single column under postcodes_covered? Taking into account that there are many many post code areas!
Or should I be adding a second table called postcodes which links to the members table? If so how would you go about linking a post code area eh "SW1" to the relevent members and what would the search query look like when someone enters a postcode in the search bar?
Use a separate table with all the postcodes. Then you can use a wildcard to find all the matches:
SELECT *
FROM members m
JOIN postcodes p ON m.id = p.member_id
WHERE p.postcodes_covered LIKE 'SW1%'

define many entities and search at single entity type at solr

I have database with 4 tables which is person,location,cities,countries now i want to be able to search in every particular table (like search for all countries start with united) and also search in all of them once (like search for all person who have locations in city start with 'c' in country 'united state').
I have tried to define entity for every table and nested entity for the last case, but i don't have an idea how to just write the query to do the up searches to tell solr that i want to search in persons only or in all tables.
Please i need code example to solve this.
I'm using php/mysql.
If you have defined an Entity for each table as well as a Combined one, you can add an identifier to each of the entity and use that identifier to filter the results.
e.g.
Add a field type to each entity with fixed values as PERSON, LOCATION CITY ....
And for queries use fq=type:PERSON to filter the results for the specific entity.

MySQL relations for country region and town tables

I am trying to figure out the best method to relate country, region and town tables.
On my website I want the user to be able to just enter a town. Then optionally country and region, both of which will be required to be entered or not at all.
Currently my tables are as such
tbl>User has townID (FK)
tbl>town has id(PK) townName regionID(FK DEFAULT NULL)
tbl>region has id(PK) regionName countryID(FK NOT NULL)
tbl>country has id(PK) countryName
I thought to possibly further spit the user to town relation to:
tbl>User has locationID (FK)
tbl>location has id (PK) townID(FK) regionID(FK) countryID(FK)
But I think that is unnecessary and just further complicates the issue?
The country database is already populated. I intend to build up my own references of town > region > country relations as entered by users. So if a user enters a town with no region and country then it is entered into tbl>town without a regionID if there isn't already a town with the same name without a region ID. This is same for a town where a region and country ID has been entered by the user. Only I check that there isn't already a town > region > country relation that already exists before entering. Later on in the development of the site I will be providing Ajax suggestions for country/region based upon the town entered by a user.
So to the questions:
I can envisage pitfalls with this such as duplicate data or data possibly being overwritten. Is there a better way to construct the tables to fit in with my desired methods?
This might get answered by the prior question: but is there anything I can do to reduce the PHP processing of the tables. Obviously I'd prefer to just insert with one PHP statement but I think there are too many caveats to do it at once.
Also as the users town entry may be null and may or may not contain a foreign key reference to a region how is it best to create a View that takes that into consideration?
As it will be hosted I would rather not be using MySQL functions.
Please let me know if you need any clarification. I really want to get this right the first time before continuing, so your help will be invaluable.
I don't think you reduce the code because it's much too explicit. You can change it, but it won't be better.
Accepting a town name without a region and country is like letting someone enter their first name without their middle or last. It's data, but it's not an identifier.
Fullerton's full name is "Fullerton, California, USA". By not requiring Fullerton's full name, you abandon foreign keys for data integrity. ("Fullerton, California, USA" is a city; "Fullerton, Alabama, USA" is not.) Good luck with that.
If you're going down this path, the best advice I can offer you is get rid of the id numbers. ISO publishes standard codes for countries and subdivisions of countries. You can look them up in Wikipedia. Storing natural keys will reduce the number of joins from 3 to zero. Zero joins is almost always going to out perform 3 joins.
You'll probably need to use outer joins to create your views.

Should I Populate Country/Region Names at DB or Application Level?

I'm going through a tough decision (at least for me)...
My website would have a list of countries in dropdown list and list of cities based on chosen country. I decided to populate the list at db level as:
CREATE TABLE Country
(
countryID - PK
countryName - FK
);
CREATE TABLE City
(
cityID - PK
countryID - FK
cityName
);
CREATE TABLE Register
(
registerID - PK
cityID - FK
)
However, this can add some complexity in php back-end coding when inserting record into registration as well as retrieving record from countries/cities, because on registration form user will city name on droplist, user won't see cityID, so i will have to fetch cityID based on chosen cityName, etc. Therefore, i said why do i just put the countries and cities list at application level in fixed drop down list and make register table look as:
CREATE TABLE Register
(
registerID - PK
cityName
)
cityName gets inserted directly without us having to join or call multiple tables and get specific ID for a city so we can then grab the cityName, etc...
I will only normalize in crucial tables such as making relationships between Member and Post/Thread tables. A member can have multiple threads one-to-many relationship. Otherwise, things that relate to multi-value as countries list won't be considered at DB level for simplicity and rap sake.
What do you think? Advice ...
The nature of the data should drive the database model. Not your front end issues.
Why not load your cities into a drop down list? Set the display text=cityName. Set the value=cityID.
Not sure I understand the text of your question completely, but to answer the title of your question, I would keep country names in the database. Countries/Cities do change their names from time-to-time.
I would suggest defining XML with the country name/id as the element and city names as the child elements. It makes it edit/read the xml data. I'm not sure whether you would like to consider this.

Categories