I have such structure:
// all objects have valid mapping to database
public class Child {
private int id;
private String name;
}
public class Parent {
private int id;
private String name;
private List<Child> chidlren;
}
and I have to update specific child B inside parent A.
There are two ways:
Update child's fields inside collection and update the whole object:
Parent temp = dao.getParent(id);
temp.getChildren.get(0).setName('test');
dao.updateParent(temp);
Update only child object:
Child temp = dao.getChild(id);
temp.setName('test');
dao.updateChild(temp);
Which one is better if I want to get more perfomance?
Thank you
On the surface, I would surmise that the second solution
2.Update only child object
would be more performant.
However, the only way you determine this quantitatively would be to turn on Hibernate's show_sql, capture the SQL for Solution 1 and Solution 2, run an Explain Plan for each of your solutions, and compare the resulting Explain Plans.
You could get differing results depending on what else has changed/not changed in the Parent object and other children in the Parent.children collection. When capturing SQL for Explain Plans, you would want to try different scenarios.
Related
I have data as shown as below. Here if Team 1 is parent & having 2 child Team A & Team B. Team A is again a parent & having player names as child. Team B does not have any child.
Again in another scenario, Team A is independent parent & contains some child etc..
If i give Team 1, then it should fetch records of Team A & Team B as a bundle.
If i give Team A, then it should fetch records of Team A containing its child.
I was thinking to implement this using Map or Tree . and I tried this -
public class Node {
private String id;
private List<Node> children = new ArrayList<>();
private Node parent;
..........
//setters and getters
}
but here creating node dynamically is problem because we don't know the levels of parents(in this example there are 2). means "Dhoni" again contains some child like wise.
How to implements this ?. Please guide.
Whatever i understood from problem description i will try to summarize here.You are looking for a data structure which can take parent name(key) and it might have children, and each child also further can be extended.
public class Node {
private String id; // for each level you have key defined.
private List<Node> children = new ArrayList<>(); //using given key you can get children list
}
You can use map here
Map<String, List<Node>> // here key is team name etc., and list represents children.
If you give team1 as key, you get list which contains teamA, teamB. So if you want to check further, check list size, if it is greater than zero, you can get children(Further you can get all the players defined for both teamA,teamB) otherwise you are at last child.
I have following classes:
public class Note extends RealmObject {
#PrimaryKey
private String id;
private Template template;
// other primitive fields, getters & setters
}
public class Template extends RealmObject {
private String name;
private String color;
// other primitive fields, getters & setters
}
I get my data from backend via Retrofit & Gson, so I have ready-to-use java objects in response.
Let's imagine that backend returns me same three Notes each time I call it.
When I get the list of Note objects, I do the following:
private void fetchNotesAndSave() {
List<Notes> notes = getNotesViaRetrofit();
Realm realm = Realm.getInstance(mContext);
realm.beginTransaction();
realm.copyToRealmOrUpdate(notes);
realm.commitTransaction();
realm.close();
}
After that I call these lines to check count of stored objects:
int notesCount = mRealm.where(Note.class).findAll().size();
int templatesCount = mRealm.where(Template.class).findAll().size();
For the first time:
notesCount == 3;
templatesCount == 3;
That's right. But, if I call the server again, get same notes (same primaryKey ids), and call fetchNotesAndSave() again, I'll get these results:
notesCount == 3;
templatesCount == 6;
Each time I call copyToRealmOrUpdate(), nested objects, that are inside of objects with primaryKey are duplicated - not updated.
Is there any way to change this behaviour?
Please let me know if you need more information. Thanks in advance!
It is because your Template class doesn't have any primary key. In that case these objects are inserted again as there is no guarantee that the referenced template objects safely can be updated, even if they are part of another object that has a primary key.
If you add a #PrimaryKey to your template class it should work as you expect it to.
If you can't provide a PK as suggested, you might want to use the following work around to avoid duplicates.
for (Note note: notes) {
realm.where(Note.class)
.equalTo("id", note.getId())
.findFirst()
.getTemplate()
.deleteFromRealm();
}
realm.copyToRealmOrUpdate(notes);
I have a plain class named MenuModel in Java (it's for nested menu as the name suggests) like this:
public class MenuModel {
public String id;
public String parentId = null;
public String title;
public MenuModel parent = null;
public List<MenuModel> children = new ArrayList<MenuModel>();
}
My code fetch data from web API and generate a flat list of MenuModel with only id, parentId, and title fields filled with data. However, I need each MenuModel to have references to its parent and (optionally) children for further uses.
I have thought of a method which make a nested loop to pair the models each other and check if they are parent and child. But I think that costs too much (n^2 or n^3 complexity, the itemset is large) and can only fill the parent field.
What is the best way to achieve this in Java? To summarize:
Input: ArrayList<MenuModel> source
Output: ArrayList<MenuModel> result containing all MenuModel from source which has parentId = null (that means, it's top level menu), with each MenuModel has children fields filled with reference to their respective children MenuModel. Additionally, each children have reference to their parents.
Thanks in advance
Go through all the records and add them to a HashMap<String, MenuModel> (the key being the ID).
Then, for each record record:
Look up the parent ID in the above map to get parent.
Assign the parent to this record's parent variable - record.parent = parent.
Add this record to the parent's list of children - parent.children.add(record).
Running time: Expected O(n).
So I have a class with three fields that maps to a table using hibernate
Class Widget
{
String field1;
String field2;
String field3;
}
On application startup a number of instances these widgets will be added to the database from an external files, but when I exit the application I need to know which (if any) of these fields have been changed by the user since the application was started, so the changes can be saved back to the files. I also need to store the original value for logging purposes.
I can't work whether I need a status field in the table or whether there is already a way of doing this using Hibernate/Database.
EDIT:A good solution to the program was given below . however the main reason I am using Hibernate is to reduce memory consumption so storing the original values when changed is not a good solution for me , I want everthing stored in the database. So I have create this new question How do I store a copy of each entity I add to database in Hibernate
Given an entity like the following you can track changes on one of it's field (while preserving its original value too).
#Entity
#Table(schema = "test", name = "test")
public final class Test {
private static final int ORIGINAL = 0;
private static final int CURRENT = 1;
private Integer id;
// holds the original and current state of the field
private final AtomicReferenceArray<String> field = new AtomicReferenceArray<>(2);
#Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Transient
public String getOriginalField() {
return field.get(ORIGINAL);
}
#Basic
public String getField() {
return field.get(CURRENT);
}
public void setField(String field) {
this.field.compareAndSet(ORIGINAL, null, field);
this.field.set(CURRENT, field);
}
#PreUpdate
public void preUpdate() {
System.out.format("Original: %s, New: %s\n", getOriginalField(), getField());
}
...
}
If there is a single row in a database like this:
id: 1
field: a
version: 2011-12-02 11:24:00
before the field gets updated (say, from a to b) you'll get the following output.
Original: d, New: b
The original value gets preserved even if the the entity is updated multiple times and both state can be accessed through the corresponding getters (getField and getOriginalField—you can get more creative than me in the naming :).
This way, you can spare yourself from creating version columns in your database and also can hide the implementation details from clients.
Instead of an AtomicReferenceArray you could use arrays, lists, etc, to track all changes like this way.
The #PreUpdate isn't necessary of course, but this way you can be notified of changes in the entity's state and atomically save the updated fields into file. There more annotations like these: see the documentation for javax.persistence for other annotation types.
If you are using MySql then you can get table's last update time from information_schema database like
SELECT UPDATE_TIME FROM `information_schema`.`tables`
WHERE TABLE_SCHEMA = 'dbName' AND TABLE_NAME = 'tableName'
Or else simple solution will be to add a column for update time stamp. By this you can even monitor which particular row has been updated.
If you need to synchronize with files as soon as you save into database, You can use the Hibernate event mechanism to intercept any save to database and save it to file, here's a sample doing that.
I'm having a bit of trouble mapping the following:
public class Operation {
private Integer id;
private String name;
private List<Item> items = new ArrayList<Item>();
//set/getters/hashcode/etc. omitted
public void addItem(Item i,Operation end) {
i.setOperationStart(this);
i.setOperationEnd(end};
items.add(i);
end.getItems().add(i);
}
public class Item {
private Integer id;
private String name;
private Operation operationStart;
private Operation operationEnd;
//set/getters/hashcode/etc. omitted
}
So basically an Operation have a bunch of Items, and an Item belongs to 2 Operations.
Also, it doesn't make sense for an item to exist if one of the Operations doesn't exist, i.e. if I delete one of the Operations, I want to remove the item from wherever else it's stored as well.
Does anyone have a pointer on how I'd map the above classes, or could point me to some examples showing how to map a child object that has 2 parents ?
From an object oriented point of view what is represented looks like two ManyToOne associations between Item and Operation, one of them being bidirectional. This could be mapped like this:
#Entity
public class Item {
#Id private Integer id;
private String name;
#ManyToOne
private Operation operationStart;
#ManyToOne
private Operation operationEnd;
//set/getters/hashcode/etc. omitted
}
#Entity
public class Operation {
#Id private Integer id;
private String name;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy="operationStart")
private List<Item> items = new ArrayList<Item>();
//set/getters/hashcode/etc. omitted
}
This should result in an [ITEM] table having two FKs pointing on [OPERATION]. And populating the items collection would result in a SELECT restricted to one of them (the ID of the start operation in the above example).
I don't know if this scenario makes sense but this is IMO the only scenario Hibernate can handle. If this is not what you want, then I think you should have two collections on the Operation side (that you could maybe hide behind friendly methods).
Whether you use hbm.xml or annotations doesn't make any difference.
This sounds like a combination of a many-to-many relation between Items and Operations, and a ternary relation between one Item and two Operations.
Assuming that your business logic is fixed on exactly two Operations per Item, and not more than that, I'd tackle this problem as follows:
If you want a clean object model, then create an intermediate object to hold the references to the two operations, and it should hold one item as a component.
Map the items in the hbm. Basically, each Operation should have a list of the intermediate object, and each intermediate object has one Item. When you delete an intermediate object, cascade the delete to the item, but not to the operations.
The tricky part, as you said, is when you delete an operation. Whether you use an intermediate object or not, you need to cascade the delete to the list with all-delete-orphan. However, I suspect that you'll have some issues due to 2nd level cache. The only way I know around that is this:
before deleting an operation op1, traverse the object graph and detach each intermediate object from its other operation op2, and only then flush. Otherwise hibernate will refuse to delete the intermediate objects because they are still held in some sets in other Operations.