Suppose we have two related tables, for example one representing a person:
PERSON
name
age
...
current_status_id
and one representing a status update at a specific time for this person:
STATUS_HISTORY
recorded_on
status_id
blood_pressure
length
...
I have built an application in PHP using Zend Framework, and tried to retain 'object orientedness' by using a class for representing a person and a class for representing the status of a person. I also tried to use ORM principles where possible, such as using the data mapper for separating the domain model from the data layer.
What would be a nice (and object oriented) way of returning a list of persons from a data mapper, where in the list I sometimes want to know the last measured blood_pressure of the person, and sometimes not (depending on the requirements of the report/view in which the list is used). The same holds for different fields, e.g. values computed at the data layer (sum's, count's, etc.).
My first thought was using a rowset (e.g. Zend_Db_Rowset) but this introduces high coupling between my view and data layer. Another way might be to return a list of persons, and then querying for each person the latest status using a data mapper for requesting the status of a specific person. However, this will result in (at least) one additional query for each person record, and does not allow me to use JOINS at the data layer.
Any suggestions?
We have this same issue because of our ORM where I work. If you are worried enough about the performance hit of having to first get a list of your persons, then query for their statuses individually, you really have no other choice but to couple your data a little bit.
In my opinion, this is okay. You can either create a class that will hold the single "person" data and an array containing "status_history" records or suffer the performance hit of making another query per "person". You COULD reduce your query overhead by doing data caching locally (your controller would have to decide that if a request for a set of data is made before a certain time threshold, it just returns its own data instead of querying the db server)
Having a pure OO view is nice, but sometimes impractical.
Try to use "stdclass" class which is PHP's inbuild class, You can get the object of stdclass which will be created automatically by PHP and its member variable will be column name. So u can get object and get the values by column name. For example.
Query is
SELECT a.dept_id,a.dept_name,a.e_id,b.emp_name,b.emp_id from DEPT a,EMP b where b.emp_id=a.e_id;
Result will be array of stdclass objects. Each row represents one stdclass object.
Object
STDCLASS
{
dept_id;
dept_name;
e_id;
emp_id;
emp_name;
}
You can access like
foreach($resultset as $row)
{
$d_id = $row->dept_id;
$d_nam= $row->dept_name;
$e_id = $row->e_id;
$em_id= $row->emp_id;
$e_nam= $row->emp_name;
}
But
Blockquote
I am not sure about performance.
Related
Let's say I have a DbTable_Product table class that represents a table product. When I query that table i.e.
$myProducts = $productTable->fetchAll();
I get a resultset of DbTableRow_Product objects. This is fine and it's the way I've done it forever.
I've just now come up against a problem for a second time in two projects, in which I want to be more specific with the object types returned in the resultset.
For instance, let's say almost all of the products don't have any special behaviour, so using the generic DbTableRow_Product class is suitable for them. But there is one difficult product that does need additional behavior.
Say there's a class I've created called DbTableRow_Product_Phone that inherits from DbTableRow_Product. I want the table object to return DbTableRow_Product objects when the resulting row is not a phone, and DbTableRow_Product_Phone when it is, all in the same resultset.
I've done this in a previous project by overriding the fetchRow, fetchAll, getRowClass and createRow methods in the table object to create the correct type of object. This works but it seems dirty.
Is there an easier way of creating different object types in a resultset, depending on the type of row? Does this approach even make sense?
I use yii framework that implements Active Record pattern as ORM base. It has CActiveRecord class that is a table wrapper class with attributes reflecting table columns. So each object of this class represents a database row.
Wiki says about Active Record pattern:
Active record is an approach to accessing data in a database
and
A database table or view is wrapped into a class. Thus, an object instance is tied to a single row in the table.
So far so good.
But where should I put complex raw sql query that retrieves statistics data for example?
And, more generally, where should I put methods that retrieve some data that can not be an active record object (like data retrieved with aggregation queries) or if I knowingly do not want to retrieve an object but an array instead for example?
And for complex queries you can always use DAO if you want:
http://www.yiiframework.com/doc/guide/1.1/en/database.dao
But in most cases, CDbCriteria will fit your needs, you can read more about it here:
http://www.larryullman.com/2013/07/24/using-cdbcriteria-in-the-yii-framework/
There are many possibilities depending on what you want. Yii has relations to access related objects and one of the relation type is statistical relation, check this link:
http://www.yiiframework.com/doc/guide/1.1/en/database.arr#statistical-query
You may also use naming scopes to filter some of your results and then call for example count function to retrieve number of filtered results (this will be done by sending select count(*) ... to db server rather than fetching all entries, so it's very convenient). Check this for named scopes:
http://www.yiiframework.com/doc/guide/1.1/en/database.ar#named-scopes
If statistical data is related to your model, for example total spending by some client (although this could be done easily using statistical relation), you can add public function directly to your model class, such as
public function getTotalSpending() {
return 0; // or whatever you need to calculate here
}
Finally it is not considered a good practice to map your business logic directly to tables. Instead create your models by subclassing CModel or CFormModel classes and add public methods that retrieve / modify data (possibly using other models that do inherit CActiveRecord class).
Use CArrayDataProvide
Elements in the raw data array may be either objects (e.g. model objects) or associative arrays (e.g. query results of DAO). Make sure to set the keyField property to the name of the field that uniquely identifies a data record or false if you do not have such a field.
source: http://www.yiiframework.com/doc/api/1.1/CArrayDataProvider
Do not ever use Active Record pattern.
I have a domain model and a data mapper built with PHP and MySql. Some domain objects appear only in the context of others and in these cases I am using dependent mappings, i.e. the dependent objects do not have their own mapper, but are instead persisted by their owner's mapper.
For performance reasons I am joining multiple tables and issuing one SQL query, (rather than one query per table), and this is where the difficulty arises: the results of my queries are cartesian joins (of course) and will require a fair amount of array sifting to get sensible data with which to populate domain objects.
For example, I have three tables: one parent (P1) and two children (C1 and C2). If a single record in P1 has two records in both C1 and C2, I have four records in my result set. I can cycle through the result set array looking for unique values and create a fresh array from these, but that seems like a lot of work.
This is bound to be a common problem. What is the typical way to solve it? I looked through the SPL data structures and iterators but didn't find anything useful. I don't want to split into multiple queries unless I really have to.
Thanks!
I currently have about 4 different database tables which output to html tables. Each of these tables uses a count query to calculate data from a 5th table.
That's no problem, but what about when I want to sort and order the data, and paginate etc (like with zend). If it were a one page table, I could probably sort an array.
My thought was, to use a ticker. But that would require a new column in all 4 tables and seems like overkill or like there could be a better way.
Sadly, I can't find much info on it (likely because I don't know what to search for).
Advice?
..and please take it easy, I'm new and learning.
Assuming youre using Zend_Db_Table_Row and that you dont need to persist any modifications you might make to these rowsets then you can just append the virtual columns to the row object and have them be accessible via array notation. So if youre doing it all in one query now just use that same query, and the column should be there.
OTOH, if youre using a Data Mapper pattern then simply adjust your hydration to look for this "virtual column" and hydrate it if it exists in the result data. Then in your getter for this property have it see if the property is null or some other negative specification, and if it is, to execute a calculation query on that single object or return the already calculated result.
I have a MySQL database containing these tables:
sessions
--------
sessionid (INT)
[courseid (INT)]
[locationid (INT)]
[comment (TEXT)]
dates
-----
dateid (INT)
sessionid (INT)
date (DATE)
courses
-------
...
locations
---------
...
Each session has a unique sessionid, and each date has a unique dateid. But dates don't necessarily have a unique sessionid, as a session can span over a variable number of dates (not necessarily consecutive).
Selecting each full row is simply a matter of joining the tables on the sessionid. However, I'm looking for a way to return a rowset for a particular courseid, where each row in that rowset represents a location, and contains another rowset, each containing single session, which in turn contains another rowset, which contains all of the dates for that session:
course
location
sesssion
date
date
session
date
date
date
location
...
This is because I'm using querying this database from PHP using Zend Framework, which has a great interface for manipulating rows and rowsets in an object-oriented manner.
Ultimately, I'm trying to output a 'schedule' to the view, organized first by course, then location, then date. Ideally, I'd be able iterate over each row as a location, and then for each location, iterate over each session, and then for each session, iterate over each date.
I'm thinking of doing this by querying for all the locations, sessions, and dates separately. Then, I'd convert each rowset into an array, and add each sessions array as a member of a locations array, and add each dates array as a member of a sessions array.
This, however, feels very kludgy, and doesn't provide me with the ability to handle the rows in an object-oriented manner.
I was wondering if there was either:
a) a better table schema for representing this data;
b) an sql query which i'm not aware of;
c) a method in Zend_Db that allows me to assign a rowset to a rowset
Please let me know if I haven't been clear anywhere, and thanks in advance.
(Crossing my fingers that this doesn't end up on the daily wtf...)
I've run into lots of issues with using Zend Frameworks database abstraction classes when I have to deal with data from multiple tables. The number of queries that run and the overhead of all of the objects generated has brought my hosting server to it's knees. I've since reverted back to writing queries to gather all of my data and then walking the data to build my display. It's not a pretty or OO as using the abstraction layers but it's also not making my PHP scripts page to disk just to display a table full of data.
As Steve mentions benchmark whatever solution you end up with, I'd also profile your memory usage.
You could handle this scenario using the relationship features of Zend_ Db_ Table. You'd need to create table wrapper classes for sessions, dates, courses, etc. if you're using Zend_ Db_ Aadpter for your queries currently.
http://framework.zend.com/manual/en/zend.db.table.relationships.html
It's not too different from the approach you described of querying for each dataset separately, but it gives you a straight forward OO interface for retrieving the appropriate related data for a given record.
You'll want to do some benchmarking if you go this route, as it could potentially execute a lot of queries.