GroupDescriptor in SL4B2 - silverlight-4.0

Using Silverlight4, how can I make datagrid grouping look up a display name from another table when the grouping value is a foreign key?
I could denormalise the entity so that it resolves the join itself but this introduces update issues. The approach that leaps to mind is a value converter and I shall look into it, but if you have a definite answer any advice would be appreciated.
NOTE
Using a join inside a view works nicely, although you do then have to explicitly handle updates. There are, however, other problems associated with grouping in datagrids. Expanding or collapsing a group causes the datagrid's CurrentItem to be NULL which seems to break the bindings for any comboboxes bound to lookups on the same DataContext. If anyone has a solution or at least advice on how to re-bind the comboboxes that would be appreciated; in the interim I have abandoned the use of grouping.

You can't do it directly. Use a view and handle update explicitly. Grouping breaks combobox lookups so if you have those abandon hope of grouping.

Related

Select columns mid Matillion transformation job

I'm a new Matillion user so suspect I'm overlooking an obvious answer...
I am currently reading a number of identically formatted tables (yearly sales data) and vertically stacking them using a Unite component. As I am exploring the data rather building a pipeline with a specific function I would like to keep as much flexibility as possible. Hence, I would like to select columns after the unite component has run. I appreciate I can easily do such column selections reading the data in at the point of running Table Input components.
Am I missing the obvious solution?
A humble Rename Component can help with that. Add one immediately after the Unite, and in the column mapping choose Add All. Then you can choose which columns to drop, mid-transformation, using the minus button.
The Rename Component's primary purpose is to add alias names, but it does double up as a good way to slim down the column selection. As a bonus side effect, doing that can improve performance.

How to ORDER BY PRIMARY KEY on Views?

I am currently making old programs HANA-ready. I work with the hints from ACI and I am on delete adjacent duplicates. Mostly an easy task. Just put an ORDER BY PRIMARY KEY and it's fine. However, on inner joins and views I get the following error:
"ORDER BY PRIMARY KEY" does not work for views. Use "ORDER BY f1 ... fn" instead.
Now my question: How do you handle this?
I don’t really have the time to deep dive in the code and understand the whole program to find a logic based solution. Is there a fast way to sort views so they have always the same order on HANA as they have on R/3?
Views have no technically defined primary keys, so ORDER BY PRIMARY KEY does not work. You also can not do something to make it "have always the same order on HANA as they have on R3" because the sort order is determined by whatever database software you are using, and with many of them it can happen that JOINs over multiple tables do not always return results in the same order. A nasty source of impossible to reproduce bugs I had to deal with more than once.
But if your view is just one table or an INNER JOIN of two or more tables, then the real primary key of the result set is pretty easy to determine: It's the combinations of all the primary key fields of the tables you join on.
But please note that slapping ORDER BY PRIMARY KEY on every SELECT is the quick&dirty way of making a program HANA-ready. It's usually much better to think for a couple minutes what sort order would actually make sense in this case.
When the results later get reduced to unique results with DELETE ADJACENT DUPLICATES, then you need to make sure that the internal table is sorted by those fields which get compared here. So when there is a list of fields (like DELETE ADJACENT DUPLICATES COMPARING date time bukrs) then you need to sort by those fields. When there are no fields, then you need to sort by all fields. Which you can actually do much simpler in ABAP with simply SORT itab.
Or when the sorting order is indeed completely irrelevant in this particular case, slap on the pseudo-comment "#EC CI_NOORDER to the SELECT to clearly communicate that order does not matter here (to both the database and to other developers).
Yes, that takes some time. But converting an older system to S/4HANA is not a task you do in a single day. It's a large project which usually takes months to complete.
No, there’s no magic button in the database that can guess what your desired sort order should be.
Even with other databases ABAP never guaranteed the sort order in the absence of explicit ORDER BY.
If the programs depend on that without specifying ORDER BY that’s a fault in those programs.
Ad: “no time...” you’re about to pay back technical debt, that got incurred when the programs got developed with that fault.
If you have HANA, then you your system is new enough for CDS views, and those can have keys.
So you just need to replace your old database view with a CDS view, add they key keyword to the necessary fields and you are done.

Create table from table/view?

I have a weird scenario. I tried to see if I could find any help on the topic, but I either don't know how to search for it properly, or there is nothing to find.
So here is the scenario.
I have a table A. From Table T_A, I created a view V_B. Now, I can make UPDATES to V_B, and it works just fine. Then when I create a view V_C which is an UNION of T_A and T_D, the view V_C is un-Updateable. I understand the logic behind why that is the case.
But my question is, is there something I can do where I combine 2 tables and am able to update?
Maybe in a way have table T_D extend T_A?
Some extra information: T_A has items 1-10 and T_D has items 100 - 200. I want to join them so there is a table/view which is updateable that has items 1-10 and 100-200.
If you have a non-updatable view, you can always make it updatable by defining instead of triggers on the view. That means that you would need to implement the logic to determine how to translate DML against the view into DML against one or both of the base tables. In your case, it sounds like that would be the logic to figure out which of the two tables to update.
A couple of points, though.
If T_A and T_D have non-overlapping data, it doesn't make sense to use a UNION, which does an implicit DISTINCT. You almost certainly want to use the less expensive UNION ALL.
If you find yourself storing data about items in two separate tables, only to UNION ALL those two tables together in a view, it is highly likely that you have an underlying data model problem. It would seem to make much more sense to have a single table of items possibly with an ITEM_TYPE that is either A or D.
It may be possible to make your view updatable if you use a UNION ALL and have (or add) non-overlapping constraints that would allow you to turn your view into a partition view. That's something that has existed in Oracle for a long time but you won't find a whole lot of documentation about it in recent versions because Oracle partitioning is a much better solution for the vast majority of use cases today. But the old 7.3.4 documentation should still work.

How to keep group and item NSTableViews in sync?

I'm working on an app for which I'd like to do something very similar to the problem proposed in this question: How to add row-span in view-based NSTableView?
The second answer intrigues me as a clever solution, but I can't figure out how to keep the two table views in sync with each other. In particular, I don't see any obvious way to make sure that the rows in the item table view show up next to the group the correspond to. The most obvious solutions to me are:
Basing the data source of the items table on that of the group table view. So, each object in the group data source has a list of the items that belong to it, then each time the item table view needs a row, iterate through the groups, and count the items in each group until you find the one you need. This sounds horribly inefficient.
Some clever application of NSSortDescriptors on the items such that they end up sorted so the rows match up. This seems kind of magic to me, like you'd be lucky if you could get it to work deterministically.
Keep a pointer to the current group you're processing through and return the next item in the group until you've exhausted the group's items, then move on to the next group. This would depend on the table view asking for rows in sequential order. Seems like this would also be really difficult if there was any concurrency or out-of-order-ness anywhere.
All of these solutions have some pretty obvious flaws. I feel like I'm missing the "trick" here, or maybe just the giant purple elephant standing in front of me. :)
Edit: In response to rdelmar's comment, I'll add a few clarifications. For my particular case, the number of items in a group is variable — some groups could have two, others ten. The solution I'd like to find shouldn't depend on there being a fixed number of items in a group.
In terms of selection behavior, it's probably not necessary that each item in a group be selectable, but they do need to be editable. Groups will probably be edited as a whole, i.e. the user will say "I want to edit group A", which will trigger the ability to edit any field in the group or the items that belong to it. It's probably possible to use labels instead of a table view, but it seems like that would involve duplicating a lot of work the table view would give you for free (arranging views in a grid, etc).
The very first solution I came up with for this actually involved embedding a table view for the items inside each row of the group table view. So, the top-level table view would consist only of groups, then each group would have its own embedded table for displaying the items it has. I eventually gave up on that solution in hopes of finding one that involved a shorter view tree.

How to prevent a derived value (SUM) from being manually updated to an incorrect value

I am learning SQL and DB design for a college class. One assignment that was given to us is to create a table with a derived attribute which is the SUM of some child attributes. For example:
ORDERS
orderID {PK}
/orderTotal /* derived from SUM of child itemTotals */
ITEMS
itemNo {PK}
orderID {FK}
itemTotal
Now, I am not even sure this is good practice. From some reading I've done on the web, derived values should not be stored, but rather calculated by user applications. I can understand that perspective, but in this instance my assignment is to store derived values and more importantly to maintain their integrity via triggers, which are relatively new to me so I am enjoying using them. I'd also imagine in some more complex cases that it really would be worth the saved processing time to store derived values. Here are the safeguards I've put in place which are NOT giving me problems:
A trigger which updates parent /orderTotal when new child item is inserted.
A trigger which updates parent /orderTotal when child item is deleted.
A trigger which updates parent /orderTotal when child itemTotal is modified.
However, there is another safeguard I want which I cannot figure out how to accomplish. Since the parent attribute /orderTotal is derived, it should never be manually modified. If somebody does attempt to manually modify it (to an erroneous value which is not actually the correct SUM), I want to either (a) prevent them from doing this or (b) revert it to its old value as soon as they are done.
Which is the better approach, and which is possible (and how)? I am not sure how to accomplish the former, and I tried to accomplish the latter via either a trigger or a constraint, but neither one seemed appropriate. The trigger method kept giving me ORA-04091 error for attempting to mutate the table which fired the trigger. The constraint method, I do not think is appropriate either since I'm not sure how to do such a specific thing inside a constraint check.
I am using Oracle SQL by the way, in SQL Developer.
Thanks!
"Now, I am not even sure thise is good practice."
Your intuition is right: this is bad practice. For some reason, a lot of college professors set their students the task of writing poor code; this wouldn't be so bad if they at least explained that it is bad practice and should never be used in the real world. But then I guess most professors have only a limited grasp on what matters in the real world. sigh.
Anyhoo, to answer your question. There are two approaches to this. One would be to use a trigger to "correct" i.e. swallow the change. This would be wrong because the user trying to modify the value would probably waste a lot of time trying to discover why their change wasn't sticking, without realising they were breaking a business rule. So, it's much better to hurl an exception.
This example uses Oracle syntax, because I'm guessing that's what you're using.
create or replace trigger order_header_trg
before insert or update
on order_header for each row
begin
if :new.order_total != :old.order_total
then
raise_application_error
( -20000, 'You are not allowed to modify the value of ORDER_TOTAL');
end if;
end;
The only problem with this approach is that it will prevent you inserting rows into ORDER_LINES and then deriving a new total for ORDER_HEADER.
This is one reason why denormalised totals are Bad Practice.
The error you're getting - ORA-04091 - says "mutating table". This happens when we attempt to write a trigger which selects from the table which owns the trigger. It almost always points to a poor data model, one which is insufficiently normalised. This is obviously the case here.
Given that you are stuck with the data model, the only workaround is a clunky implementation using multiple triggers and a package. The internet offers various slightly different solutions: here is one.
One solution might be to move all the logic for maintaining the orderTotal into an INSTEAD OF UPDATE trigger on the ORDERS table.
The triggers you already have in ITEMS can be simplified to update ORDERS without making a calculation - setting orderTotal to 0 or something like that. TheINSTEAD OF` trigger will run in place of the update statement.
If an attempt is made to manually update the order total, the INSTEAD OF trigger will fire and re-calculate the existing value.
PS - I don't have an Oracle DB to test on, but from what I can tell, an INSTEAD OF trigger will get around the ORA-04091 error - aplologies if this is wrong
EDIT
Whilst this solution would work in some other RDBMS systems, Oracle only supports INSTEAD OF triggers on views.
EDIT 2
If the assignment allows it, a view could be a suitable solution to this problem, since this would enable the order value column to be calculated.