Business Objects Generating Unexpected Query - business-objects

I am having problem with BusinessObject Universum and the way it generates queries and consequently yielding the results.
Here is the background: mechanism that is functioning has already been implemented. I was trying to copy the SAME mechanism just to deliver a different field.
Here is the data model: http://tinypic.com/r/ng524g/8
The mechanism that functions is marked with BLUE color. The mechanism that I tried to implement and that is not functioning is marked with RED color.
On business layer I have defined a dimension with aggregate aware function. This function takes first VWF_Party_Collection_A.Collectionstatus_CD column (at the higher level). If a user selects an attribute from contract level, function takes VWF_Contract_Collection_A.Collectionstatus_CD column.
Problem is when I take all attributes from VWD_Kunde_A table and than add the dimension with the mentioned aggregate aware function (ie Collectionstatus_CD), the constructed query from BO side does not make any sense. Here it is:
SELECT
D_ATA_MV_FinanceTreasury.VWF_Party_Collection_A.Collectionstatus_CD,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Namespace_TXT,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Party_KEY,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Legacy_ID
FROM
D_ATA_MV_FinanceTreasury.VWD_Party_A
LEFT JOIN D_ATA_MV_FinanceTreasury.VWF_Party_Collection_A
ON D_ATA_MV_FinanceTreasury.VWD_Party_A.Party_KEY=D_ATA_MV_FinanceTreasury.VWF_Party_Collection_A.Party_KEY,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A
WHERE
(
D_ATA_MV_FinanceTreasury.VWD_Party_A.Party_KEY=D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Party_KEY )
AND
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Legacy_ID = 102241978
Please notice the strange conctruction in the 'FROM' part (comma has been added). Another strange and unexpected construction is in 'WHERE' part:
( D_ATA_MV_FinanceTreasury.VWD_Party_A.Party_KEY=D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Party_KEY )
The mechanism that is functioning is joining joins VWD_Kunde_A with VWF_Contract_Collection_A table and yields the correct result.
Now, I have tried to define a dimension without the mentioned aggregate aware function that contains only VWF_Contract_Collection_A.Collectionstatus_CD attribute. When I run the same query BO yields CORRECT results and it generates the CORRECT (expected) query.
This is the query I am expecting:
SELECT
D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A.Collectionstatus_CD,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Namespace_TXT,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Party_KEY,
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Legacy_ID
FROM
D_ATA_MV_FinanceTreasury.VWD_Kunde_A LEFT JOIN D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A ON D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Namespace_TXT = D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A.Namespace_TXT AND D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Party_KEY = D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A.Party_KEY AND D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Legacy_ID = D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A.Legacy_ID
WHERE
D_ATA_MV_FinanceTreasury.VWD_Kunde_A.Legacy_ID = 102241978
Furthermore, I suspected that it can something to do with contexts. However, I did not find any context for the mechanism that already functions and that I tried to copy. Therefore, I did not implement any context for the mechanisam I am tring to implement.
At this point I am clueless since I tried everything I knew. I would appreciate help.
Thanks!
A.
UPDATE: it seems as aggragate aware function is not functioning... This is how it is defined:
#Aggregate_Aware(D_ATA_MV_FinanceTreasury.VWF_Party_Collection_A.Collectionstatus_CD,D_ATA_MV_FinanceTreasury.VWF_Contract_Collection_A.Collectionstatus_CD)
(I just copied the code from Kreditklasse and adapted it... That makes me even more confused...)
UPDATE_2: it really seems as if aggragate aware is not functioning in my case because I selected all attributes from contract_context and it still jumps to party context. Very confused because THE SAME mechasism is functioning as expected when I select Kreditklasse...

Check the aggregate navigation.
Setting up Aggregate Awareness requires two steps (in addition to correctly defining the joins between the tables, of course):
Define the objects with the Aggregate_Aware function
Set table-object incompatibilities through Actions > Set Aggregate Navigation.
It sounds like the second part is not properly configured: make sure that any objects which require the second table are marked incompatible with the first.

Related

Yii2 is there a way to specify tablename in ActiveQuery conditions (like andWhere) in a nice and short way

I make a query (with \yii\db\ActiveQuery) with joins, and some fields in "where" clause become ambigous. Is there a nice and short way to specify the name of the current model`s (ActiveRecord) table (from which one the ActiveQuery was instantiated) before the column name? So I can use this all the time in all cases and to make it short.
Don't like doing smth like this all the time (especially in places where there're no joins, but just to be able to use those methods with joins if it will be needed):
// in the ActiveQuery method initialized from the model with tableName "company"
$this->andWhere(['{{%company}}.`company_id`' => $id]);
To make the "named scopes" to work for some cases with joins..
Also, what does the [[..]] mean in this case, like:
$this->andWhere(['[[company_id]]' => $id]);
Doesn't seem to work like to solve the problem described above.
Thx in advance!
P.S. sorry, don't have enough reputation to create tag yii2-active-query
to get real table name :
Class :
ModelName::getTableSchema()->fullName
Object :
$model::getTableSchema()->fullName
Your problem is a very common one and happens most often with fields liek description, notes and the like.
Solution
Instead of
$this->andWhere(['description'=>$desc]);
you simply write
$this->andWhere(['mytable.description'=>$desc]);
Done! Simply add the table name in front of the field. Both the table name and the field name will be automatically quoted when the raw SQL is created.
Pitfall
The above example solves your problem within query classes. One I struggled over and took me quite some time to solve was a models relations! If you join in other tables during your queries (more than just one) you could also run into this problem because your relation-methods within the model are not qualified.
Example: If you have three tables: student, class, and teacher. Student and teacher probably are in relation with class and both have a FK-field class_id. Now if you go from student via class to teacher ($student->class->teacher). You also get the ambigous-error. The problem here is that you should also qualify your relation definitions within the models!
public function getTeacher()
{
return $this->hasOne(Teacher::className(), ['teacher.id' => 'class.teacher_id']);
}
Proposal
When developing your models and query-classes always fully qualify the fields. You will never ever run into this problem again...that was my experience at least! I actually created my own model-gii-template. So this gets solved automatically now ;)
Hope it helped!

Gerrit REST API: cannot use _sortkey to resume a query

I'm using Gerrit REST API to query all changes whose status is "merged". My query is
https://android-review.googlesource.com/changes/?q=status:merged&n=2
where "n=2" limits the size of query results to 2. So I got a JSON object like:
Of course there are more results. According to the REST document:
If the n query parameter is supplied and additional changes exist that match the query beyond the end, the last change object has a _more_changes: true JSON field set. Callers can resume a query with the N query parameter, supplying the last change’s _sortkey field as the value.
So I add the query parameter N with the _sortkey of the last change 100309. The new query is:
https://android-review.googlesource.com/changes/?q=status:merged&n=2&N=002e4203000187d5
With this new query, I was hoping that I'll get another 2 new query results, since I provided the _sortkey as a cursor of my previous search results.
However, it's really weird that this new query returns exactly the same results as the previous query, instead of the next 2 results as I expected. It seems like providing "N=002e4203000187d5" has no effect at all.
Does anybody know why using _sortkey to resume my query doesn't work?
I chatted with one of the developers at Google, and he confirmed that _sortkey has been removed from the newer versions of Gerrit they are running at android-review and gerrit-review. The N= parameter is no longer valid. The documentation will be updated to reflect this.
The alternative is to use &S=x to skip x results, which I tested and works well.
sortkey is deprecated in Gerrit v2.9 -
see the (Gerrit) ReleaseNotes-2.9.txt, under REST API - Changes:
[[sortkey-deprecation]]
Results returned by the [query changes] endpoint are now paginated using offsets instead of sortkeys.
The sortkey and sortkey_prev parameters on the endpoint are deprecated.
The results are now paginated using the --limit (-n) option to limit the number of results, and the -S option to set the start point.
Queries with sortkeys are still supported against old index versions, to enable online reindexing while clients have an older JS version.
See also here -
PSA: Removing the "sortkey" field from the gerrit-on-borg query interface:
...
Our solution is to kill the sortkey field and its related search operators (sortkey_before, sortkey_after, and resume_sortkey).
There are two ways you can achieve similar functionality.
Add "&S=" to your query to skip a fixed number of results.
(Note that this redoes the search so new results may have jumped ahead and
you might process the same change twice.
This is true of the resume_sortkey implementation as well,
so your code should already be able to handle this.)
Use the before/after operators.
Instead of taking the sortkey field from the last returned change and
using it in a resume_sortkey operator, you take the updated field from
the last returned change and use it in a before operator.
(This has slightly different semantics than the sortkey field, which
uses the change number as a tiebreaker when changes have similar updated times.)
...

MySQL Spatial Within function gives errors

I have a table of areas which has an AREA_ID column and an AREA column which is a Polygon type.
I am running the following query but I cannot seem to get it to work:
SELECT AREA_ID, AsText(AREA)
FROM networkmodel.sit_area
WHERE Within(AREA, Polygon((
50.913424 -1.420527,
50.915805 -1.391516,
50.898053 -1.390142,
50.895021 -1.428251,
50.913424 -1.420527)))
This query gives me an "Operand should contain 1 column" error.
If I put one less set of brackets around my coordinates I get an "Illegal non geometric '(50.913424 -1.420527)' value found during parsing" error instead. Are my coordinates the wrong format?
I am aware from the MySQL documentation that the Within function has not been implemented properly and falls back to the MBR implementation instead but I am just testing it out at the moment. I have used the Contains function in the past with success to return me records in a similar way by using a Point as the second parameter instead of a polygon and this is supposed to be the opposite of that.
It is my understanding from the documentation that this function takes two parameters and checks whether the first (my areas column in this case) falls within the given Polygon.
Any help is appreciated thanks.
Right I made it work now, Instead of using this function I had to change the Polygon declaration to:
GeomFromText('Polygon((50.913424 -1.420527, 50.915805 -1.391516, 50.898053 -1.390142, 50.895021 -1.428251, 50.913424 -1.420527))')

LINQ-to-SQL performance question

I am getting an IQueryable from my database and then I am getting another IQueryable from that first one -that is, I am filtering the first one.
My question is -does this affect performance? How many times will the code call the database? Thank you.
Code:
DataContext _dc = new DataContext();
IQueryable offers =
(from o in _dc.Offers
select o);
IQueryable filtered =
(from o in offers
select new { ... } );
return View(filtered);
The code you have given will never call the database since you're never using the results of the query in any code.
IQueryable collections aren't filled until you iterate through them...and you're not iterating through anything in that code sample (ah, the beauty of lazy initialization).
That also means that each of those statements will be executed as its own query against the database which results in no performance cost over doing two completely independent queries.
SO is not a replacement for developer tools. There are many good free tools able to tell you exactly what this code translates into and how it works. Use Reflector on this method and look at what code is generated and reason for yourself what is going on from there.

Stopping LINQ from querying entity sets (and grouping)

This is a brief description of my db. You have issues which have categories. I have various queries that get issues based on all sorts of criteria, but that's not important to the question.
I want to be able to take a list of issues I have queried, lets say for example, that occured yesterday and group them by category.
I have a method:
public static IEnumerable<Category> GroupIssuesByCategory(IEnumerable<Issue> issues)
{
return from i in issues
group i by i.Category into c
select c.key
}
Category has a nice mapping which allows it to list Issues within it. That's great for what I want, but in this scenario, it will pull back all the issues in that category, rather than the ones from the set I provided. How do I get around this?
Can I get around this?
I worked out why my original code wasn't compiling and updated the question.
Alas, I still have my main problem.
I'm not sure about the second part of the question, but your compilation problem is that the return type of a grouping is IEnumerable<IGrouping<Category, Issue>>, which I think is what you are looking to return from your method. Also, you don't really need the into c select c bit - that's only useful if you want to do some processing on the result of the grouping to get a different list.
IGrouping<S,T> has a key property which is the Category value, and is IEnumerable<T> to give you the list of Issues in that Category.
Try this as your method:
public static IEnumerable<IGrouping<Category, Issue>> GroupIssuesByCategory(IEnumerable<Issue> issues)
{
return from i in issues
group i by i.Category;
}