Join a Flat Table to an EAV Table with Magento? - collections

I am trying to manke an Adminhtml Grid which joins a table that I made called "facility" to "customer_entity" and all of its attribtues.
I'm noticing that since my table is flat, and the model inherits fomr Mage_Core_Model_Mysql4_Collection_Abstract, I'm not able to use all the class_methods that I've seen as examples on the backend.
I've successfully been able to join my table to the customer_entity table doing the following:
$collection = Mage::getModel('facility/facility')->getCollection()
->join('customer/entity', 'customer_id = entity_id');
However, what I really need is just to get the customer name. Any help?

Customer names are not stored in one field, they are a combination of first, middle and last name; and depending on settings, a prefix and suffix too. The customer classes have methods for combining these for you.
$collection = Mage::getModel('customer/customer')->getCollection()
->addNameToSelect()
->joinTable('facility/facility', 'entity_id=customer_id', array('*'));
The joinTable method is part of EAV collections which is why you won't see it in the core MySQL4 based collections. The first parameter is not a literal table name but an entity table as described in your config.xml.

Generally I agree with the previous answer just some corrections to the syntax
$collection = Mage::getModel('customer/customer')->getCollection()
->addNameToSelect()
->joinTable('facility/facility', 'customer_id=entity_id', array('*'), null, 'right');
null part is a WHERE clause and the 'right' is the type of the join
Or maybe a better decision is:
$collection = Mage::getModel("facility/facility")->getCollection()->getSelect()->join('customer_entity', 'entity_id=customer_id', array('*'));

Related

How to get all the columns name of a DB table in SilverStripe

I am new to SilverStripe and I want to perform a simple query using SilverStripe functions (I don't want to use raw SQL). I want to get all the columns' names of the product table.
So far, I didn't find anything useful in the SilverStripe documentation. I appreciate any suggestion.
You have to understand that the Silverstripe $db (Data Model / ORM) and database columns are not always in sync. If you delete a $db attribute, the column will still exist in your database, but no longer in your ORM. Source
Assuming you want the current ORM-attributes, you can simply use, for a Dataobject $record:
$attributes = $record->toMap();
Even more attributes (even inherited attributes) can be collected by using the schema:
$schema = \SilverStripe\ORM\DataObject::getSchema();
$allFields = $schema->fieldSpecs($record);
$columns = array_keys($allFields);

Force 'fetch joined' relations to include IDENTITY of their ManyToOne relations using HYDRATE_ARRAY?

I have a query in which I'm joining a number of tables to my original Person entity. A Person may have multiple Child relations (OneToMany), and a Child may have a School they go to (ManyToOne). Problem is, I don't need the entire School entity that connects to each child, only their id, which is already stored on Child.
I'm using a Paginator to iterate through the results and I use HYDRATE_ARRAY to reduce overhead of the ORM parsing data to entity objects. But the id fields of unfetched relations are not returned this way, and thus, the School id isn't either.
I may join the School entity too, but since the identity is already stored on the Child records, I don't see why I should further reduce performance by having the database join another table. Fetching results as entity objects would also solve the problem, but also at the cost of performance. How can I get the id to apper the results without having to unnecessarily join the the School entity or having to hydrate the results as objects?
$query = $em->getRepository(Entity\Person::class)->createQueryBuilder('p');
$query
->select([
'p as person',
'w.name as workplace_name',
'c',
])
->leftJoin('p.children', 'c') //Entity\Child
->leftJoin('p.workplace', 'w') //Entity\Company
//...
;
$paginator = new Paginator($query);
$paginator->getQuery()
->setHydrationMode(\Doctrine\ORM\Query::HYDRATE_ARRAY);
You can use Doctrine\ORM\Query::HINT_INCLUDE_META_COLUMNS to include the foreign key column values in the result:
$paginator->getQuery()
->setHint(\Doctrine\ORM\Query::HINT_INCLUDE_META_COLUMNS, true)
->setHydrationMode(\Doctrine\ORM\Query::HYDRATE_ARRAY);
which:
The includeMetaColumns query hint causes meta columns like foreign keys and discriminator columns to be selected and returned as part of the query result.
Reference
Doctrine\ORM\Query documentation
How to get association foreign key IDs in Doctrine 2 without loading the associated object?
Getting only ID from entity relations without fetching whole object in Doctrine

Symfony - Doctrine QueryBuilder produces wrong sql

I am trying to build a query via query builder.
$photosQuery = $photoRepository->createQueryBuilder('p')
->join('AppBundle:User', 'u')
->where('LOWER(p.title) LIKE :phrase OR LOWER(u.username) LIKE :phrase AND p.isActive = :isActive AND p.isModerated = :isModerated')
->setParameter('phrase', '%'.strtolower($phrase).'%')
->setParameter('isActive', true)
->setParameter('isModerated', true)
->getQuery();
It gives me
SELECT p0_.id AS id_0,
p0_.title AS title_1,
p0_.description AS description_2,
p0_.name AS name_3,
p0_.creation_date AS creation_date_4,
p0_.edit_date AS edit_date_5,
p0_.is_moderated AS is_moderated_6,
p0_.moderation_date AS moderation_date_7,
p0_.is_active AS is_active_8,
p0_.user_id AS user_id_9,
p0_.category_id AS category_id_10
FROM photos p0_
INNER JOIN users u1_ ON (LOWER(p0_.title) LIKE ?
OR LOWER(u1_.username) LIKE ?
AND p0_.is_active = ?
AND p0_.is_moderated = ?)
Why are my WHERE parameters in the join ON() portion and not a traditional WHERE?
Thank you!
Doctrine provides a wrapper around lower-level database connections that to not necessary have all the features present in DQL. As such, it emulates some features (such as named parameters, or splitting array parameters into multiple separate values).
You're seeing that in action here: the named parameters are converted into positional parameters in the raw query. Doctrine still knows what the mapping is, though, and is able to correctly order them when the query and parameters are sent to the server.
So the answer from jbafford explained some information Doctrine but did not explicitly answer why the ON was used instead of the WHERE, and it stems from a common mistake (of which I recently made as well).
In your query, when you use
->join('AppBundle:User', 'u')
you are simply telling the query builder that you need to join on the User table, but it doesn't specifically know that you want to join on the user association of your Photo entity. You may think - why doesn't this happen automatically? Well, imagine if you had 2 another association on your table that linked to a User entity as well (maybe a createdBy field or similar). In that case Doctrine wouldn't know the association you wanted.
So, instead the proper thing to do is join directly on your association rather than generically on the entity, like so:
->join('p.user', 'u')
and then Doctrine will handle the rest. I couldn't actually tell you why it uses the where() condition for the join, unless it's just assuming that's what you wanted, since it needs to know how to join on something.
So just remember that when you are joining on an association you already defined, join on the association as described in your entities rather than thinking of it in a straight SQL format where you'd join on the table.

How do you join two tables in Doctrine2 using Query Builder if the table relationships are not setup?

I am currently using Symfony2 and Doctrine2 and am trying to join two tables together using query builder.
The problem I have is that all my annotated entities do not have the table relationships setup. I will at some point address this, but in the mean time I need to try and work round this.
Basically I have two tables: a product table and a product_description table. The product table stores the basic information and then I have a product_description table that stores the description information. A product can have one or more descriptions due to language.
I want to use query builder, so I can retrieve both the product and product_description results as objects.
At the moment I am using the following code:
// Get the query builder
$qb = $em->createQueryBuilder();
// Build the query
$qb->select(array('p, pd'));
$qb->from('MyCompanyMyBundle:Product', 'p');
$qb->innerJoin('pd', 'MyCompanyMyBundle:ProductDescription', 'pd', 'ON', $qb->expr()->eq('p.id', 'pd.departmentId'));
$query = $qb->getQuery();
$products = $query->getResult();
This gives me the following error:
[Syntax Error] line 0, col 71: Error: Expected Doctrine\ORM\Query\Lexer::T_DOT, got 'MyCompanyMyBundle:ProductDescription'
Can anyone point me in the right direction? I am up for doing it differently if there is an alternative.
Without having the relationships defined, I don't think you can join the tables. This is because when you use DQL, you're querying an object rather than a table, and if the objects are unaware of each other, you can't join them.
I think you should look at using a NativeQuery. From the docs:
A NativeQuery lets you execute native SELECT SQL statements, mapping the results according to your specifications. Such a specification that describes how an SQL result set is mapped to a Doctrine result is represented by a ResultSetMapping. It describes how each column of the database result should be mapped by Doctrine in terms of the object graph. This allows you to map arbitrary SQL code to objects, such as highly vendor-optimized SQL or stored-procedures.
Basically, you write raw SQL, but tell Doctrine how to map the results to your existing entities.
Hope this helps.

Complex datasource issue in Dynamics AX

I have a grid that displays lines from a table. Now, I have these two requirements:
Show only the lines that contains values in the "hour" fields. The "hour" field is an array type.
Show the lines from a project and its subproject
My problem is this: to meet requirement #1, I need to use a select statement in my datasource since I cannot access array value using QueryBuildDataSource (this is a known limitation in Dynamics AX).
But to meet requirements #2 I need to have two "exists join", and this is not possible in Dynamics AX. For example the following code would not work:
select from table where
exists join tableChild where projectId = MyProjectId OR
exists join tableChild where parentProjectId = MyProjectId
How would someone address this issue?
From the select statement example you provided, it appears it may not be necessary to have two exist joins. A single exists join with the "OR" for the two possible conditions in its where clauses may be sufficient, of course, you should still have some relationship between table and tableChild for the join to make logical sense.
select from table
exists join tableChild
where (tableChild.projectId = MyProjectId || tableChild.parentProjectId = MyProjectId)
You can use array values in query ranges providing field IDs using fieldID2Ext function.
You can build view and apply confitions on top of it.

Resources