I am working on a project of an online service provider.
I have tables for admin, agent, customer and tables for data storage like city, services, category, sub-category, gender.
I have created classes for the admin
, customer
and agent
.
But should I create classes for city
, services
, category
, etc or use as methods in admin
, customer
and agent
.
note:- I want to perform CRUD
operation for city
, services
, category
, sub-category
, gender
tables.
Is it good to have one class for each table in a database? If not then please explain how to avoid this situation? Can I use enum or ArrayList instead of class for data storage?
3 Answers 3
Put them in their own class (city, services, category, sub-category, gender). Why wouldn't you? Is there a concern that you'll have too many classes that interact with the data storage?
If you want to expand on any of these entities, there would be no reason to change the: customer, agent or admin classes. That doesn't mean a customer can't be associated with many cities in some sort of list/array, but when it comes to managing the cities themselves, why bother the customer code? If you associate a city with a country, parish or province, try not to mess with anything else.
A few months down the road, either you or a new/additional developer may need to modify how the category or sub-categories work, so wouldn't it be pretty simple to start with those classes?
If it wasn't for the design of your database, how would you handle it? Many proponents of OOP, suggest holding off on database/storage decisions until you get the business logic and requirements established.
-
Thanks. But I found that each class for each table is an anti-pattern. Will you clarify on this? Is each class for each table ORM or different?prasam mehta– prasam mehta2018年03月29日 17:41:59 +00:00Commented Mar 29, 2018 at 17:41
-
2@prasammehta - It is an anti-pattern to assume each class should have its data written to disk in only one table.JeffO– JeffO2018年04月04日 23:17:30 +00:00Commented Apr 4, 2018 at 23:17
-
3@prasammehta it seems to me that you are conflating "one class per table" with the Active Record design pattern wherein the model class is responsible for persisting itself (e.g., $customer->save()) which is often criticized due to violating SRP and introducing very tight coupling to the persistence mechanism which often presents difficulties with writing tests for your business objects. You should write your business logic first and figure out persistence later.John Hall– John Hall2018年04月20日 18:19:54 +00:00Commented Apr 20, 2018 at 18:19
-
We have one class per table and have many, many different entity classes - generally for each table in the database. It's worked very well for a few years.John Hunt– John Hunt2018年06月28日 13:03:19 +00:00Commented Jun 28, 2018 at 13:03
Yes, its normally good to have a one to one mapping between classes and tables.
The type of objects you mention are regarded as 'entity objects' in that they represent a 'real' thing, many of which exist, each with differing, but not necessarily different, data.
eg you have many customers in your database and when you want to work with one in code you instantiate a customer object, populate its data from the database and pass it around, call its methods etc.
You can have other types of object which don't follow this rule. For example you might have a MailSenderService
with methods like MailSenderService.SendMailToCity(City city)
There's no point have a MailSenderService table, its just the one object with some logic used to send mail in it.
-
Thanks for the answer. But what about
city
,services
,category
,sub-category
,gender
which don't have extra behaviour except for CRUD operations. These tables are justbyproducts
of data normalization inRDBMS
. These tables store data which are used asreference data
in other tables. ex. city_id in agent and customer tables. Can I userepositories
for CRUD operation andarray list
for data storage?prasam mehta– prasam mehta2018年03月29日 14:34:58 +00:00Commented Mar 29, 2018 at 14:34 -
all of them, I was just using customer as an exampleEwan– Ewan2018年03月29日 18:48:09 +00:00Commented Mar 29, 2018 at 18:48
Think about it from the different perspective and recall that there is no silver bullet design.
What are you trying to achieve by your design? Do you want to have your data completely consistent or optimized for performance?
I have tables for admin, agent, customer and tables for data storage like city, services, category, sub-category, gender.
Admin, Agent and Customer sounds like entities in your domain. You will implement some business logic around them, so it makes sense to define appropriate classes. Usually data for each of such classes is contained inside single table in DB (could not be the case for derived entities).
City could be seen differently. Does city have some properties, like references to services or category (exactly this direction of relationship) or like country name? If I try to remove city from DB, should I remove all customers associated with city or at least prevent removal of city? If the answers for these questions is "Yes", then city has some properties, thus it is some entity in your business domain and it should be defined as class. If the answer is "No" and you know that city in your domain is just name of city, then you don't have to define city as class.
From programming perspective, would you like to work with something like $customer->getCity()->getName()
(city defined as entity) or $customer->getCity()
(city defined as string)? In the first case, you will always have JOIN at some point, either during fetching of $customer
from DB (eager strategy) or during call to getCity()
(lazy strategy). In the second case, city will be inlined in same table as customer, thus you will have better performance for bulk operations (like fetching 10K customers with your ORM).
Ok, city is pretty complicated entity to discuss without knowledge of your problem domain, but e.g. gender is definitely doesn't worth defining as class. How often are you going to change gender in your system? Do you even really need CRUD for it or is getting list of gender enough? From my development experience, we had gender as enum for 3 years without making any change to list of genders. It is pretty safe bet that you can define it as enum.
Concrete mechanism of connecting such enum as Gender to property depends on your framework of choice. E.g. in Doctrine you could use https://github.com/fre5h/DoctrineEnumBundle/ to implement abstract enums for property. Concrete values of choices for enum could be fetched from database during cache warmup or app initialization, for example.
Remember, the more interconnected entities you have, the more performance problems you will have in future (because of JOINs performed during every query). In the end, design can evolve, and performing data migrations is not that hard if you have suitably designed database on every step of application life (at least you have primary keys and foreign keys that reflect your domain). The best way to start designing you app/database is:
- Understand problem domain (what entities are there, what data flows you have).
- Build ERD of your business domain (good starter book on the topic could be "Learning MySQL" by Hugh Williams, Seyed Tahaghoghi).
- Create first version of database schema and evolve it over time accordingly to upcoming business requirements.
- Add app-database connection code to fit your database design (usually database lives longer than code).
Another good book for reading is "Refactoring Databases: Evolutionary Database Design" by Scott W. Ambler, Pramodkumar J. Sadalage.
TL;DR Don't try to fit design accordingly to tools that you have, instead create design that is appropriate for your problem domain and pick tools that will help to implement it.
Hope this provides some insight.
Explore related questions
See similar questions with these tags.
enum
orArrayList
instead ofclasses
for data storage and repository forCRUD
operations?