hibernate when merging object sets field to null - sql

I have a class that goes:
#Entity
#Table(name = "TRANSACTIONS")
public class Transaction {
#Id
#Column(name = "TX_ID")
private Long id;
#Basic
#Column(name = "AMOUNT")
private Double amount;
#Column(name = "AMOUNT_COST")
private Double amountCost;
#NotNull
#Column(name = "AMOUNT_TAX")
private Double amountTax;
#NotNull
#Column(name = "BANKACCOUNT")
private String bankAccount;
//getters and setters here
}
the problem is, when I create Transaction object, and fill data, and then I want it to merge, hibernate merges it with fields AMOUNT_COST and BANKACCOUNT set to null. I checked with debugger - the object I want to merge is correctly filled with data, AMOUNT_COST is set to 0.0 and BANKACCOUNT is correct.
I have no clue what might be the problem here:
-I double checked column names
-I double checked my sql table, and types of data
-I tried to put annotations on getters, or on declaration of variable - nothing changes.
When I set columns to 'nullable' then the object is merged with null values, but only for those two fields (!). I'm clueless here, so I really need a hint. Thanks in advance.

ha. I forgot to mention that I'm using extended entity menager, and in this case, it was it's fault.

Related

Working non-working Hibernate Derby error

I have this very simple entity with the exact same annotations I use prior to adding it to the project. I get the stacktrace below,shown and also, not shown, when adding the FK constaint. The error occurs whether I use the primitive or object for the index. Everything seems correct, can someone edify me? ty.
#Setter
#Getter
#NoArgsConstructor
#Entity
public class User {
#Id
#GeneratedValue
int user_id;
private String name;
private String email;
private String password;
#ManyToMany
#JoinTable(name = "user_role",joinColumns = #JoinColumn(name = "user_id"),inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
}
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error
executing DDL "create table user (user_id integer not null, email
varchar(255), name varchar(255), password varchar(255), primary key
(user_id))" via JDBC Statement at
org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase.accept(GenerationTargetToDatabase.java:67)
~[hibernate-core-5.4.17.Final.jar:5.4.17.Final]
I know, I know DTFS, Sorry, for the clutter and lost cycles of attention;)

Filter on relationship's field

I'm trying to fetch all entities for a given relationship's field match (I want my entity's relationships filled out in the result). Trying with Filter on session.loadAll() to filter on the relationship's field but I can't make it work.
My entities definition looks like:
#NodeEntity
class ClockAction {
#Id #GeneratedValue
private Long id;
private String description
private User user;
private Office office;
}
#NodeEntity
class User {
#Id #GeneratedValue
private Long id;
private String name;
private List<ClockAction> clockActions;
}
#NodeEntity
class Office {
#Id #GeneratedValue
private Long id;
private String name;
private List<ClockAction> clockActions;
}
From that I'm need to retrieve all ClockAction entities where User.id is in a given set of Ids.
Here is my try :
Filter filter = Filter("id", ComparisonOperator.IN, userIds);
filter.setNestedPropertyName("user");
filter.setNestedPropertyType(User.class);
filter.setNestedRelationshipEntity(true);
return session.loadAll(ClockAction.class, filter);
This always returns an empty result. Any idea of what I'm doing wrong?
Using a session.query like this
session.query(ClockAction.class, "MATCH p=(a:ClockAction)-[r]-() WHERE id(r) IN {ids} RETURN nodes(p), rels(p), a, r ORDER BY a.id", params)
works but only office field of ClockAction gets filled out on the result entity, user is always null...
Any help is appreciated :)
Some things first:
It is unfortunately currently not possible to filter for an id field because the filters only work with properties. Id fields are queried in cypher with the id function. (id(n) != n.id)
You are not looking for a relationship entity (remove filter.setNestedRelationshipEntity(true);)
Now you have the choices:
Query for another property of the User class with the filter.
Alter your cypher query with something like this: "MATCH p=(a:ClockAction)-[r]-(n) WHERE id(n) IN {ids} RETURN nodes(p), rels(p), a, r ORDER BY a.id" The changes are based on the assumption that the code snippets are correct and User is not a relationship.
Additional information (edit):
If no relationship is defined, Neo4j OGM will create them directed outgoing from the node you are saving. Your graph could look like this (ClockAction as root):
Or like this (User as root with multiple ClockActions):
You are not getting the Office because your current query path is (:User)-[r]-(:ClockAction) there is no information in the path about an Office.
MATCH (n:User)-[ur:CLOCK_ACTIONS]->(c:ClockAction)-[or:OFFICE]->(o:Office) WHERE id(n) IN {ids} RETURN c, n, ur, o, or is a pretty straight forward query you could use. It removes the path centric style but also loads all the data you need.
If the graph was stored through the User but this is just an example and can be applied however the data looks in your graph, you won't see any User information on the ClockActions because as it saves without any hint Neo4j OGM will also expect the data related in a outgoing direction from the class you want to load.
Now it is necessary, keeping the User example, to add a #Relationship(type="CLOCK_ACTION", direction = "INCOMING") to the user field in your ClockAction class.
This will give Neo4j OGM the needed hint to put the User data it has in your user field.
I ended up following advises from #meistermeier and annotate my relationships giving direction.
Below is my model entities :
#NodeEntity
class ClockAction {
#Id #GeneratedValue
private Long id;
private String description
#Relationship(direction = Relationship.OUTGOING)
private User user;
#Relationship(direction = Relationship.OUTGOING)
private Office office;
}
#NodeEntity
class User {
#Id #GeneratedValue
private Long id;
private String name;
#Relationship(direction = Relationship.INCOMING)
private List<ClockAction> clockActions;
}
#NodeEntity
class Office {
#Id #GeneratedValue
private Long id;
private String name;
#Relationship(direction = Relationship.INCOMING)
private List<ClockAction> clockActions;
}
What #meistermeier suggested for query did not work for me, but gave me inspiration and I found this working fine :
MATCH p((u:User)-[ur]-(c:ClockAction)-[or]-()) WHERE id(u) IN {ids} RETURN p, rels(p)

Entity data reset when a lazy LOB is changed

I'm working on a big project using Glassfish 4 (JavaEE7) and EclipseLink (JPA2.1).
When I modify the value of a LOB field, this resets all the previous value of then entity.
For instance, I have the following entity:
#Entity
#Table(name="person")
public class Person implements Serializable {
#Id
#Column(name = "ID")
private Integer id;
#Column(name = "LASTNAME")
private String lastname;
#Column(name = "FIRSTNAME")
private String firstname;
#Column(name = "VERSION")
private Integer version;
#Lob
#Basic(fetch = FetchType.LAZY)
#Column(name = "REMARKS")
private String remarks;
/* getter & setters */
}
I use the following code to update my entity:
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
#Startup
public class ModifierBean implements ModifierBeanLocal {
#Resource
private UserTransaction userTransaction;
#PersistenceContext
private EntityManager entityManager;
#Override
public String modify(Integer id, String lastname, String firstname, String remarks) {
try {
StringBuilder result = new StringBuilder(256);
userTransaction.begin();
Query query = entityManager.createQuery("SELECT p FROM Person p WHERE p.id = ?1");
query.setParameter(1, id);
Person p = (Person)query.getSingleResult();
result.append("State 0: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setFirstname(firstname);
p.setLastname(lastname);
p.setVersion(p.getVersion()+1);
result.append("State 1: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
p.setRemarks(remarks); // <= reset the other fields
result.append("State 2: lastname=").append(p.getLastname()).append(", firstname=").append(p.getFirstname()).append(", version=").append(p.getVersion()).append("<br />");
userTransaction.commit();
return result.toString();
} catch(Exception e) {
//...
}
}
}
When I'm running the following code, here is the output I get from the Bean:
State 0: lastname=Smith, firstname=John, version=0
State 1: lastname=John2, firstname=Smith2, version=1
State 2: lastname=Smith, firstname=John, version=0
As one can see, the values of then entity are reset when LOB is loaded, which is very annoying for my purpose.
There are some tricks to prevent that to happen, for instance I tested the following options:
call entityManager.flush() just before the modification of the LOB field
call p.getRemarks() juste before doing the first modifications
I also noticed that if the LOB field is not changed, then the values are correctly committed.
I know that a LAZY value is loaded on demand but I do not understand why it resets all the other values.
Is this a bug or a standard behaviour ? Is there any way to make it work as expected (no reset of value) ?
I just found out that this exact bug has been open in EclipseLink (already present since v2.1.3): https://bugs.eclipse.org/bugs/show_bug.cgi?id=371743
It would depend on your persistence unit properties and it's assocation to the transaction. I believe though, since you haven't explicietely joined the EntityManager to the transaction, the Em is behaving as if it is outside the transaction causing the following behavior to apply:
"Outside transaction entire object (fetch group members included) is refreshed in the shared cache."
http://wiki.eclipse.org/EclipseLink/Development/2.1/AdvancedJPA_Queries/FetchGroup
Try calling entityManager.joinTransaction(); after starting the transaction to see if this helps. EclipseLink

Synchronize two lucene documents mapped for the same table (entity)

Consider two identical Java entities (PersonM1, PersonM2) mapped for the same table (PERSON) with the same attributes defined as:
#Entity
#Table(name = "PERSON")
#Indexed
public class PersonM1 {
#Id
#DocumentId
private long id;
#Field
#Column
private String name;
//setters, gettes, ...
}
#Entity
#Table(name = "PERSON")
#Indexed
public class PersonM2 {
#Id
#DocumentId
private long id;
#Field
#Column
private String name;
//setters, gettes, ...
}
Is there a way to update PersonM2 indexes when we update a PersonM1 object?
If The object PersonM1 is updated, changes are persisted on the database, but not in PersonM2 index directory, so PersonM2 indexes won't be correct in this case.
Shall I do it manually (update PersonM1 when PersonM2 is updated)?
Note: Java inheritance trick is not relevant!
There is no way currently, as the identity of the indexed type is represented directly the the class instance of the model. This will change in Hibernate Search 5, so in that version you might have a "clean" solution for such a scenario but I don't know yet if we will expose an API for this, and how this would look like. You'll probably have to provide your custom implementation of "entity identity".

How to fetch data from two tables(one-to-many relations) using Hibernate Createcriteria

How to fetch data from two tables based upon User id ?
*****************Role Class***********************
#Entity
#Table(name = "IUC_CON_USER_ROLE_MAP")
public class Role {
#Id
#Column(name="F_ROLE_MAP_ID")
int rolemap;
#Column(name="F_ROLE_ID")
int roleid;
#OneToMany(mappedBy="role",fetch=FetchType.EAGER)
Set<User> F_USER_ID;
*********************User class*******************
#Entity
#Table(name = "IUC_CON_USER")
public class User implements Serializable {
#Id
#Column(name = "F_USER_ID")
private int id;
#Column(name = "F_USER_NAME")
private String name;
#Column(name = "F_USER_PWD")
private String pwd;
#ManyToOne
#JoinColumn(name="F_USER_ID",insertable=false,updatable=false)
private Role role;
----------setter and getter for properties
}
External edit:
Criteria creation code:
DetachedCriteria uCrit = DetachedCriteria.forClass(User.class, "user");
uCrit.add(Restrictions.eq("user.id", 5));
uCrit.setProjection(Projections.property("user.id"));
DetachedCriteria criteria = DetachedCriteria.forClass(Role.class, "role");
criteria.add(Property.forName("role.F_USER_ID").in(uCrit));
List lt1 = criteria.getExecutableCriteria(getSession()).list();
use createAlias
criteria.createAlias("propertiy_of_main_entity", "aliastName");
For me this fetches entities asociated with root entity via some entity property name;
in your case something like
createAlias("F_USER_ID", "roleUsers");
should do.
Anyway why ins't your field name following commong naming doctrine for Java? WHY_IS_IT_UPPERCASED_WITH_DASHES_LIKE_CONSTANTS_?
All in all everything is explained in Hibernate documentation. If alias won't work, than fetch associations like in examples from Hibernate documentation under link I provided.
You can use below series of statements to fetch User along with the Role:
int userId = 1;
Criteria criteria = session.createCriteria(User.class);
criteria.setFetchMode("role", FetchMode.JOIN);
criteria.add(Restrictions.eq("id", userId));
User user = (User) criteria.uniqueResult();
The default fetching strategy of Hibernate is to fetch the associations lazily, which you need to override at runtime in code, if you want the associations (here the Role) to be fetched along with User. The third statement is doing this overriding by seting the fetch mode to JOIN. This statement FetchMode.JOIN overrides the default behavior, so that Role will be fetched along with the User.