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.
Related
It is easy to make relation between two tables of a database by #Relation and #ForeignKey of the Room library
And in SQLite we can join tables from different databases
But how can I do it by Room Library?
In Room you will not be able to code cross database foreign keys. The same restriction applies to SQLite. However, a Foreign Key is not required for a relationship to exist, it is a constraint(rule) used to enforce the integrity of a relationship.
Likewise in Room you will not be able to utilise cross database relationships. The #Relation annotation basically defines join criteria used the for queries that Room generates.
However, you can programmatically have relations between two room databases via the objects.
Example
As a basic example (based upon a Room database I was looking at) consider:-
The first database (already existed), whose abstract class is Database which has a single entity that is defined in the Login class and has all the Dao's in the interface AllDao.
A Login object having 4 members/fields/columns, the important one being a byte[] with the hash of the user, named userHashed.
The second database, whose abstract class is OtherDatabase which has a single entity defined in the UserLog class and has all the Dao's in the interface OtherDBDao.
A UserLog object having 3 members/fields/columns, the importane/related column being the hash of the respective user(Login) (the parent in the Login table).
With the above consider the following :-
//First Database
db = Room.databaseBuilder(this,Database.class,"mydb")
.allowMainThreadQueries()
.build();
allDao = db.allDao();
//Other Database
otherdb = Room.databaseBuilder(this,OtherDatabase.class,"myotherdb")
.allowMainThreadQueries()
.build();
otherDBDao = otherdb.otherDBDao();
// Add some user rows to first db
Login l1 = new Login(t1,t2,t3,10);
Login l2 = new Login(t2,t3,t4,20);
Login l3 = new Login(t3,t4,t1,30);
Login l4 = new Login(t4,t1,t2,40);
allDao.insertLogin(l1);
allDao.insertLogin(l2);
allDao.insertLogin(l3);
allDao.insertLogin(l4);
// Get one of the Login objects (2nd inserted)
Login[] extractedLogins = allDao.getLoginsByUserHash(t2);
// Based upon the first Login retrieved (only 1 will be)
// add some userlog rows to the other database according to the relationship
if (extractedLogins.length > 0) {
for (int i = 0;i < 10; i++) {
Log.d("USERLOG_INSRT","Inserting UserLog Entry");
otherDBDao.insertUserLog(new UserLog(extractedLogins[0].getUserHashed()));
}
}
UserLog[] extractedUserLogs = otherDBDao.getUserLogs(extractedLogins[0].getUserHashed());
for(UserLog ul : extractedUserLogs ) {
// ....
}
The above :-
builds both databases.
Adds 4 users to the first database.
extracts all of the Login objects that match a specific user (there will only be 1) from the first database.
for each Login extracted (again just the 1) it adds 10 UserLog rows to the other database.
as the TEST, uses the userhash from the first database to extract all the related UserLog rows from the other database.
to simplify showing the results a breakpoint was place on the loop that would process the extracted UserLog objects.
Of course such a design would probably never be used.
The following is a screen shot of the debug screen when the breakpoint is triggered :-
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.
I want to select some particular fields from my database and send them to user as json but whenever i fetch data from database using ebean it selects all the columns
Optional<User>user= server.find(User.class).where().eq("name",username)
.and().eq("password", DigestUtils.sha1Hex(password))
.select("name").findOneOrEmpty();
if(user.isPresent())
return ok(Json.toJson(user));
It shows all fields of table in json but i want only name field back.
id column automatically in map when you select column.
Use setDistinct(true) before select column, it will only select name column
Optional<User>user = server.find(User.class).where().eq("name", username)
.and().eq("password",DigestUtils.sha1Hex(password)).setDistinct(true)
.select("name").findOneOrEmpty();
if(user.isPresent())
return ok(Json.toJson(user));
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);
}
I have an android app which makes remote API calls to fetch some data.
Remote server fetches data from DB table. I have java class which maps to table columns in both Android app and on Server which sends data.
DB TABLE:
Item (
item_id bigint(20)
item_name varchar(20)
price decimal(8,2)
);
//Item class
Class Item {
private long itemId;
private String itemName;
private Float price;
//Corresponding getters/setters
}
STEP1: Remote API convert "Item" Object to JSON and send it to android app
STEP2: Mobile app casts JSON to "Item" class using JSONP
PROBLEM:
Item table on server side is bound to change and over period of time we need to add new columns. Now If I add new columns in server side "STEP2" will break thus app crashes(because of new column). I need to modify apps Item class to accomodate new column so that it won't break. But, If I modify app, app crashed for users who haven't updated app (since they have old item table).
QUESTION:
Suppose, I can send table definition when app starts. What is best way to use this JSON Map to create new Item class out of it?