Retrieve Siebel data based on intersection table using SiebelDataBean - java

I have Siebel structure looking like this:
BusObj: Base
--BusComp: Category list
----BusComp: Product list
"Product list" is child component to "Category list", they have a link Category list/Product list by the means of intersection table 'S_CAT_PROD', that has CAT_ID for category and PROD_ID for product. This allows N-to-N linking of categories to products.
Now the problem is I have retrieved both SiebelBusComp from Java code, but have no idea how to make use of this intersection table to retrive all products for some category.
There are couple SiebelBusComp methods that return another SiebelBusComp, but I had no luck making them work. These are:
getAssocBusComp()
getMVGBusComp(java.lang.String fieldName)
getPicklistBusComp(java.lang.String fieldName)
parentBusComp()
Has anyone any experience using such logic in Java? Any help would be appreciated, thanks.

I couldn't find the table S_CAT_PROD in Siebel, assuming it is custom made. Again, assuming you have a M:M link from Catalog to Products correctly configured using this intersection table , the link itself will take care of filtering the child records based on parent category.
//make variable instances
var BO = TheApplication().GetBusObject("Base");
var bcCat = BO.GetBusComp("Category list");
var bcProd = BO.GetBusComp("Product list");
//search for category
bcCat.ClearToQuery();
bcCat.SetSearchSpec("Id", "1-234");
bcCat.ExecuteQuery(True);
// When using the ExecuteQuery method with Java Data Bean, use True for //ForwardOnly and False for ForwardBackward.
if (bcCat.FirstRecord())
{
//the link will automatically filter and bring only those products for this //category
bcProd.ClearToQuery();
bcProd.ExecuteQuery(True);
}

Related

Get AUTO_INCREMENT *before* database insertion in MySQL JDBC

I'm developing a MySQL database project using JDBC. It uses parent/child tables linked with foreign keys.
TL;DR: I want to be able to get the AUTO_INCREMENT id of a table before an INSERT statement. I am already aware of the getGeneratedKeys() method in JDBC to do this following an insert, but my application requires the ID before insertion. Maybe there's a better solution to the problem for this particular application? Details below:
In a part of this application, the user can create a new item via a form or console input to enter details - some of these details are in the form of "sub-items" within the new item.
These inputs are stored in Java objects so that each row of the table corresponds to one of these objects - here are some examples:
MainItem
- id (int)
- a bunch of other details...
MainItemTitle
- mainItemId (int)
- languageId (int)
- title (String)
ItemReference
- itemId (int) <-- this references MainItem id
- referenceId (int) <-- this references another MainItem id that is linked to the first
So essentially each Java object represents a row in the relevant table of the MySQL database.
When I store the values from the input into the objects, I use a dummy id like so:
private static final int DUMMY_ID = 0;
...
MainItem item = new MainItem(DUMMY_ID, ...);
// I read each of the titles and initialise them using the same dummy id - e.g.
MainItemTitle title = new MainItemTitle(DUMMY_ID, 2, "Here is a a title");
// I am having trouble with initialising ItemReference so I will explain this later
Once the user inputs are read, they are stored in a "holder" class:
class MainItemValuesHolder {
MainItem item;
ArrayList<MainItemTitle> titles;
ArrayList<ItemReference> references;
// These get initialised and have getters and setters, omitted here for brevity's sake
}
...
MainItemValuesHolder values = new MainItemValuesHolder();
values.setMainItem(mainItem);
values.addTitle(englishTitle);
values.addTitle(germanTitle);
// etc...
In the final layer of the application (in another class where the values holder was passed as an argument), the data from the "holder" class is read and inserted into the database:
// First insert the main item, belonging to the parent table
MainItem mainItem = values.getMainItem();
String insertStatement = mainItem.asInsertStatement(true); // true, ignore IDs
// this is an oversimplification of what actually happens, but basically constructs the SQL statement while *ignoring the ID*, because...
int actualId = DbConnection.insert(insertStatement);
// updates the database and returns the AUTO_INCREMENT id using the JDBC getGeneratedKeys() method
// Then do inserts on sub-items belonging to child tables
ArrayList<MainItemTitle> titles = values.getTitles();
for (MainItemTitle dummyTitle : titles) {
MainItemTitle actualTitle = dummyTitle.replaceForeignKey(actualId);
String insertStatement = actualTitle.asInsertStatement(false); // false, use the IDs in the object
DbConnection.insert(insertStatement);
}
Now, the issue is using this procedure for ItemReference. Because it links two MainItems, using the (or multiple) dummy IDs to construct the objects beforehand destroys these relationships.
The most obvious solution seems to be being able to get the AUTO_INCREMENT ID beforehand so that I don't need to use dummy IDs.
I suppose the other solution is inserting the data as soon as it is input, but I would prefer to keep different functions of the application in separate classes - so one class is responsible for one action. Moreover, by inserting as soon as data is input, then if the user chooses to cancel before completing entering all data for the "main item", titles, references, etc., the now invalid data would need to be deleted.
In conclusion, how would I be able to get AUTO_INCREMENT before insertion? Is there a better solution for this particular application?
You cannot get the value before the insert. You cannot know what other actions may be taken on the table. AUTO_INCREMENT may not be incrementing by one, you may have set that but it could be changed.
You could use a temporary table to store the data with keys under your control. I would suggest using a Uuid rather than an Id so you can assume it will always be unique. Then your other classes can copy data into the live tables, you can still link the data using the Uuids to find related data in your temporary table(s), but write it in the order that makes sense to the database (so the 'root' record first to get it's key and then use that where required.

How to get category by name?

I recently work with commerce tools platform and I have such a question.
I have this query:
CompletionStage<List<Category>> stage = QueryExecutionUtils.queryAll(client, CategoryQuery.of().byName(Locale.ENGLISH, "cat1"));
final CompletableFuture<List<Category>> result = stage.toCompletableFuture();
return result.get().get(0);
Is there a way to return just a Category instead of List.get(0) and how it can be done?
Thanks for submitting this question. There is no unique constraint for the name field on categories. For this reason we cannot guarantee that the API will only return one result. With the name query you will get paged results and will have to pull the first entry from the list. Both key and id are both unique so you could query for either of those and get just the unique category. You can view the representation of categories in the docs here. https://docs.commercetools.com/http-api-projects-categories#category
Hope this helps!

Hibernate Envers - request for changes in a List of the object

I have a Contractor that has List of Projects he's involved with. The contract also has other lists such as Employees, payments and other fields (name, date etc).
My objective is to see which projects the contractor is associated to were changed.
example
Contractor C is involved in the following projects:
1. Furman street <Active>
2. Park West <Active>
3. Central Train Station <Active>
one day the user changes the project Park West from Active to completed etc.
So now each time I get the Contractor's revisions I get the entire information (projects, contacts, fields etc). Problem is that each time I touch the projects (list) - it goes to the db. My question, since I need to do a minimal touch to the db, how can I request projects revisions only? so I can tell what the user has done (example: add project X and mark completion for project Y)
What I have done so far is:
AuditReader reader = AuditReaderFactory.get(em);
AuditQuery query = reader.createQuery().forRevisionsOfEntity(Contractor.class, false, true).add(AuditEntity.id().eq(objID));
List<Contractor> contractors = query.getResultList();
and I also tried to ask for only projects like this (didn't work due to Null Pointer Exception )
...add(AuditEntity.property("projects").hasChanged());
public class Contractor implements Serializable
{
//fields... name, dates...
#DiffIgnore
#OneToMany(mappedBy = "contractor")
#JsonIgnoreProperties(value = {"contractor"}, allowSetters=true)
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<ContractorProject> projects = new HashSet<>(); //this is a many to many relationship for a reason
}
Based on your comments given that a Project cannot be unassigned from a Contractor once that link has been made and that you're solely interested in changes made to those said projects associated with a given Contractor instance, the best way to obtain the information in question would likely be through executing several audit queries to build that view.
The first thing you'll need is a list of Project ids that are associated to that Contractor. You could acquire this information from the audit tables but I believe it would likely be better just to obtain those directly from the normal entity data instead.
SELECT p.id FROM Contractor c JOIN c.projects p WHERE c.id = :contractorId
The above query is basically a projection-based query which given a contractor identifier, you obtain all the project identifiers that are associated to the contractor through the projects association.
Should you wish to acquire this via the audit tables instead, the first thing we'd need to determine is the maximum revision number for the contractor so we fetch the right snapshot of data.
// you might want to check if this collection is empty
// it should not be assuming you aren't removing data from the audit tables
// but sometimes people archive data, so its best to be thorough
List<Number> revs = reader.getRevisions( Contractor.class, contractorId );
// The list of revisions are always in ascending order, so grab the last entry.
Number maxRevision = revs.get( revs.size() - 1 );
// Build the projection query
// This returns us the list of project ids, just like the HQL above
List projectIds = reader.createQuery()
.forEntitiesAtRevision( Contractor.class, maxRevision )
.traverseRelation( "projects", JoinType.INNER )
.addProjection( AuditEntity.property( "id" ).distinct() )
.up()
.add( AuditEntity.id().eq( contractorId ) )
.getResultList();
Once you have this information, it comes down to executing an audit query in a loop for each Project to determine the information you need.
for ( Object projectId : projectIds ) {
List results = reader.createQuery()
.forRevisionsOfEntity( Project.class, false, false )
.add( AuditEntity.id().eq( projectId ) )
.addOrder( AuditEntity.revisionNumber().asc() );
// At this point you have an list of object array values
// Index 0 - This is the instance of Project
// Index 1 - This is the revision entity, you can get the rev # and timestamp
// Index 2 - Type of revision, see RevisionType
//
// So you can basically iterate the list in ascending order keeping track of
// the prior Project and build a changeset for each project.
//
// This approach is often more efficient if you're needing to compare multiple
// attributes on an entity rather than issuing a query to the database for
// each change made to a single property.
}
In the next major release of Envers, there will be some additional query methods that will allow you to get an object array that consists of the following
// Index 0 - This is the instance of Project
// Index 1 - This is the revision entity, you can get the rev # and timestamp
// Index 2 - Type of revision, see RevisionType
// Index 3 - Array of properties changed at this revision
The key point here is index 3 where we will provide you with the properties that were modified, so you don't have to calculate those yourself.

Custom view criteria in oracle adf

I had created one search page using custom viewcriteria with five parameters.In my search page working perfect.I have one doubt,we are entering the some parameters in the search page to get the details from one table, Here i need that values which we are entered in that boxes for using that values into a one java class.
How get those values?
Maybe ,This link can help you.you should glance
http://www.awasthiashish.com/2013/07/implementing-custom-search-form-in-adf.html
You can read the search value from a custom BC method (either on AM or VO impl level):
ViewCriteriaImpl applyVC =
(ViewCriteriaImpl)myViewObject.getViewCriteria("MyViewCriteriaName")
while(applyVC.hasNext) { Row vcrow = applyVC.next(); .... }

Saving in a web application

I have a web application (using Vaadin, Hibernate, and Postgres database) in which users can add data to a certain table. When the user adds an item to this table they are asked to enter the name, date, and selected from a table all the related products. When they click save I am able to save the name and date into the database but am having trouble grabbing the items from the table and putting them into a set to add. The bean class for the table looks like this:
/** Created by Hibernate **/
public class BeanClass implements Serializable {
private String name;
private Date date;
private Set relatedProducts = new HashSet(0);
.
.
.
}
The code I am using to save the item the user wants to add is:
BeanClass toAdd = new BeanClass();
Set temp = null
/** There is a table where the user can select all the products they want to add
* When they select an item it goes to another table, so what I am doing here
* is adding looping through latter table and adding all the items they selected
* to a set (supposedly i think this should work
**/
for (Object item : table) {
temp.add(table.getContainerProperty("id", item));
}
toAdd.setName(nameField.getValue()); //I have input fields for the name and date
toAdd.setDate(dateField.getValue());
toAdd.setRelatedProducts(temp);
hbsession.save(toAdd);
When the user clicks save the name and date is added to the table, but the relatedProducts is not added to the relationship table (in the database). I have looked into cascade and inverse in hibernate and am thinking that I will have to use these but do not quite understand how.
what datatype is your relatedProducts Set? is it another Bean, then you have to define a OneToMany annotation.
did you debug if the Set is filled before writing it to the database?
You dont really need to iterate over the whole table to get selected values. You can get the items selected via table.getValue()
getValue()
Gets the selected item id or in multiselect mode a set of selected ids.
If it's the same datatype in the table as it is in your Bean, then
toAdd.setRelatedProducts(table.getValue());
should be enough.

Categories