How to find table related with an alias in Doctrine ORM query? - orm

I'm using Doctrine ORM 1.2 and Symfony 1.4 and I want to create method in myUser class which will extend Doctrine_Query instance passed as an argument with some additional left joins and conditions. The trick is that I don't always want these these left joins to be made with root component of the query and I need to know with what table (record class) the alias corresponds - in some cases I would like to pass an alias of another component and expect it to be supplemented with some extra left joins and conditions.
My question is how can I check what component (essentially table) represents given alias? Suppose I create a Doctrine_Query instance:
$query = Doctrine_Query::create();
$query->from('Folder f')->leftJoin('f.ChildFolders cf');
Now I want my method in myUser class to add some joins to the table with alias 'cf' but varying depending on table which 'cf' aliases. I want to call it this way:
$this->getUser()->limitQueryResultsWithSomeCondition($query, 'cf');
That should return query with additional elements. How can I find out what table is symbolized by 'cf' alias and whether it exists at all in given query?
It is quite straightforward when it is root table of a query that needs to be extended, but I cannot find a way to do it in other cases.

I guess I found my own solution to the problem. To find out to which table/record given alias corresponds one has to use getQueryComponent method. Suppose the query is same as in question above. The solution then reads as follows:
$alias = 'cf';
$query->getSqlQuery();
$component = $query->getQueryComponent($alias);
$recordClass = get_class($component['table']->getRecordInstance());
The trick is that before method getSqlQuery (or some method which is called inside of this method) is called the component will not be found and exception will be thrown.

Related

AMDP selects false records contrary to OpenSQL

I am learning AMDP and I found out that the result obtained from this is very different from normal select query in ABAP AS.
I am using below code in AMDP:
ex_gt_data = select a.vbeln,
a.kunnr,
a.bukrs_vf,
b.erdat,
b.lsmeng,
b.posnr,
b.matnr
from vbak as a
join vbap as b
on a.vbeln = b.vbeln;
followed by APPLY_FILTER function.
This query return multiple values in BUKRS_VF field. If I use normal select query like below:
SELECT a~vbeln,
a~bukrs_vf,
a~kunnr,
b~erdat,
b~lsmeng,
b~posnr,
b~matnr
FROM vbak AS a
JOIN vbap AS b
ON a~vbeln = b~vbeln
INTO TABLE #DATA(lt_vbak)
WHERE a~vbeln IN #s_vbeln.
it generates required result.
Can anybody tell me why this difference between AMDP and normal select query?
I just found out that adding
MANDT
field
solves the issue. i have added an pass by value parameter in method and used in query as
where a.mandt = im_mandt.
Dont know whether this is the correct solution.Please advise.
Many discrete useful pieces were given, but I am here to give a comprehensive answer to the question.
First of all, ABAP CDS views do not respect client data automatically like it is done in OpenSQL. BTW, the same is true for HANA CDS but judging on indirect indicators of your question it was about ABAP CDS based on HANA backend, rather that HANA CDS. Ya?
What is the proper way of client handling in ABAP CDS views?
#ClientHandling.type #CLIENT_DEPENDENT annotation must be added to view.
Default type is #INHERITED but for more straightforwardness it's better make it explicitly dependent.
#ClientHandling.algorithm is an optional field and can be omitted. There is a complex set of rules which determines how the client is calculated but in your case you can just don't specify it, implicit #AUTOMATED way will be used and client column will be implicitly added to ON conditions of your JOIN.
Client column must exist in view and should be either
selected via SELECT statement with either name or alias
have MANDT name manually set
if the latter is absent CLIENT column is used
if neither CLIENT nor MANDT column is not found the syntax error is thrown
No other actions needed, client is addressed implicitly like in OpenSQL case.
But! Here we are speaking about AMDP procedure, not simple CDS, so the things are more tricky.
The first and foremost, for all this to work a special CDS SESSION CLIENT CURRENT AMDP declaration is mandatory in a method signature:
AMDP OPTIONS READ-ONLY
CDS SESSION CLIENT CURRENT
the declaration makes implicit passing of $session.client var into the implementation of AMDP procedure. In the default CURRENT syntax variant it is equal to sy-mandt value of ABAP AS.
After that you can use $session.client explicitly with tables inside AMDP
SELECT * FROM vbak WHERE vbak.mandt = $session.client;
or implicitly with client-dependent views
lt_vbak = APPLY_FILTER ("Z_CDS_VIEW", :iv_where);
You don't HAVE to add the MANDT parameter to get the client number in AMDP/generated SQL script. Rather, you can use SESSION_CONTEXT('CLIENT')
So, your above query would look like the following:
ex_gt_data = select a.vbeln,
a.kunnr,
a.bukrs_vf,
b.erdat,
b.lsmeng,
b.posnr,
b.matnr
from vbak as a
join vbap as b
on a.vbeln = b.vbeln
and a.mandt = SESSION_CONTEXT('CLIENT');
There are many more things you can achieve using SESSION_CONTEXT. Used properly, it's a powerful tool at your disposal.
Best Regards,
Gopal Nair.

Path references in QueryDSL join to subquery

I'd like to know the best way to implement this query in SQL-style QueryDSL which joins to a subquery. I struggled a bit, but got it to generate the necessary SQL. I'm wondering if there are any simplifications/improvements, however, particularly related to the three "paths" I had to create? For example, would be great to define latestCaseId in terms of latestSubQuery.
In the simplified form of my actual query below, I am finding the set of records (fields spread across ucm and pcm) which have the latest timestamp per case group. The subquery identifies the latest timestamp per group so that we can filter the outer query by it.
final SimplePath<ListSubQuery> latestSubQueryPath = Expressions.path(ListSubQuery.class, "latest");
final SimplePath<Timestamp> caseLatestMentioned = Expressions.path(Timestamp.class, "caseLatestMentioned");
final SimplePath<Integer> latestCaseId = Expressions.path(Integer.class, "latest.caseId");
final ListSubQuery<Tuple> latest = new SQLSubQuery()
.from(ucm2)
.innerJoin(pcm2).on(ucm2.id.eq(pcm2.id))
.groupBy(pcm2.caseId)
.list(pcm2.caseId.as(latestCaseId), ucm2.lastExtracted.max().as(caseLatestMentioned));
q.from(ucm)
.join(pcm).on(ucm.id.eq(pcm.id))
.innerJoin(latest, latestSubQueryPath).on(pcm.caseId.eq(latestCaseId))
.where(ucm.lastExtracted.eq(caseLatestMentioned));
I believe you could use the .get(<various Path impls>) method of PathBuilder. The way I like to think of it is that creating final PathBuilder<Tuple> latestSubQueryPath = new PathBuilder<>(Tuple.class, "latest") and joining to it .innerJoin(latest, latestSubQueryPath) is creating an alias for the subquery. Then you can use .get(<various Path impls>) to access the fields as follows:
q.from(ucm)
.join(pcm).on(ucm.id.eq(pcm.id))
.innerJoin(latest, latestSubQueryPath).on(pcm.caseId.eq(latestSubQueryPath.get(pcm2.caseId)))
.where(ucm.lastExtracted.eq(latestSubQueryPath.get(maxLastExtractedDate)));
I've not run the code but hopefully this is in the right direction. If not, I'll have a look tomorrow when I have the relevant codebase to hand.
Update: As mentioned in the comments, ucm2.lastExtracted.max() requires an alias. I've called it maxLastExtractedDate and assume it's used to alias ucm2.lastExtracted.max() when creating the subquery.

How to read a class parameter using Caché SQL?

How do I read a class parameter using Caché SQL?
select * from table does not list any class parameters.
Parameters are specific to the class definition, not specific to the object or row. Therefore, you cannot find them by querying the class table. Rather, you need to query the Class Definition tables. These reside in the %Dictionary classes.
For this particular query, you can use
SELECT * FROM %Dictionary.ParameterDefinition WHERE parent='Sample.Person'
In the SAMPLES namespace, this should yield results for all Parameters that are a part of Sample.Person - in this case, only EXTENTQUERYSPEC.

Django distinct on a specific field

class A:
name = Char...
class B:
base = ForeignKey(A)
value = Integer..
B.objects.values('a__name','value').distinct('a__name')
As you understand above, I try to get the B objects grouping by its related object's name. However, distinct function doesn't take parameter.
I have tried by annotation and aggregation but I couldn't group by a__name
I have also tried values_list with flat=True but it only takes one column name but I need both a__name and value fields.
How can I do that in Django?
Thanks
First, you need Django 1.4+. If you're running a lesser version, you're out of luck. Then, you must be using PostgreSQL. Passing a parameter to distinct does not work with other databases.
See the documentation for distinct and pay attention to the "Note" lines.
You could always issue a raw query, I suppose, as well, if you don't meet the above conditions.

What's the reasoning behind result columns being excluded from auto-select statements in PetaPoco

If I have a POCO class with ResultColumn attribute set and then when I do a Single<Entity>() call, my result column isn't mapped. I've set my column to be a result column because its value should always be generated by SQL column's default constraint. I don't want this column to be injected or updated from business layer. What I'm trying to say is that my column's type is a simple SQL data type and not a related entity type (as I've seen ResultColumn being used mostly on those).
Looking at code I can see this line in PetaPoco:
// Build column list for automatic select
QueryColumns = ( from c in Columns
where !c.Value.ResultColumn
select c.Key
).ToArray();
Why are result columns excluded from automatic select statement because as I understand it their nature is to be read only. So used in selects only. I can see this scenario when a column is actually a related entity type (complex). Ok. but then we should have a separate attribute like ComputedColumnAttribute that would always be returned in selects but never used in inserts or updates...
Why did PetaPoco team decide to omit result columns from selects then?
How am I supposed to read result columns then?
I can't answer why the creator did not add them to auto-selects, though I would assume it's because your particular use-case is not the main one that they were considering. If you look at the examples and explanation for that feature on their site, it's more geared towards extra columns you bring back in a join or calculation (like maybe a description from a lookup table for a code value). In these situations, you could not have them automatically added to the select because they are not part of the underlying table.
So if you want to use that attribute, and get a value for the property, you'll have to use your own manual select statement rather than relying on the auto-select.
Of course, the beauty of using PetaPoco is that you can easily modify it to suit your needs, by either creating a new attribute, like you suggest above, or modifying the code you showed to not exclude those fields from the select (assuming you are not using ResultColumn in other join-type situations).