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

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.

Related

JPA: single table inheritance possible performance tradeoff

I have following MS SQL DB tables, where I am storing school related data:
HighSchools<---GradeLevels<---Courses<---CourseGrades
The relations between the tables looks like
#Entity
#Table(name = "GradeLevels", schema = "dbo")
public class HighSchoolGradeLevel {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "AttendedId", nullable = false)
private HighSchoolAttended highSchoolAttended;
#OneToMany(mappedBy = "highSchoolGradeLevel")
#OrderBy("createdDate ASC")
private List<HighSchoolCourse> highSchoolCourses = new ArrayList<>(0);
// other fields and getter/setter methods....
}
#Entity
#Table(name = "Courses", schema = "dbo")
public class HighSchoolCourse {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "GradeLevelId", nullable = false)
private HighSchoolGradeLevel highSchoolGradeLevel;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "highSchoolCourse", cascade={CascadeType.REMOVE, CascadeType.PERSIST})
#OrderBy("createdDate ASC")
private List<HighSchoolCourseGrade> highSchoolCourseGrades = new ArrayList<>(0);
// other fields and getter/setter methods....
}
#Entity
#Table(name = "CourseGrades", schema = "dbo")
public class HighSchoolCourseGrade {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CourseId", nullable = false)
private HighSchoolCourse highSchoolCourse;
// other fields and getter/setter methods....
}
The java web-app users can do CRUD operations with the tables data.
The new requirement is to consume the data with the same structure from a third party. The consumed data SHOULD NOT be displayed for the web-app users.
Therefore, I am thinking to use JPA single table inheritance which allows me to:
avoid adding clones of the existing tables
avoid cloning existing business logic which is tight to existing
entity types
avoid code refactoring of existing CRUD ops in case implementing own discriminator column.
The Single table inheritance looks reasonable to use in my, but there is one thing I am not sure about "What is the performance trade off of using Single Table Inheritance, especially while operating on the Parent and its Childs entities?". The question may sound dummy, knowing the fact that Hibernate will update SQL queries with corresponding discriminator statements. But still it would be nice to improve the current knowledge and be sure that the existing users of wep-app will not get bad usage experience.
The existing web-app DAO layer uses with Spring Data JPA. Currently, each of existing tables contains more than ~500k records.

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)

Spring Data JPA. Choose all posts that contain tags

I use Spring Data. I have following entities:
#Entity
class Post {
#Id
private Long id;
private String message;
#ManyToMany
#JoinTable(name = "POST_TAG", joinColumns = {
#JoinColumn(name = "POST_ID", referencedColumnName = "ID"),
#JoinColumn(name = "TAG_ID", referencedColumnName = "ID")
})
private Set<Tag> tags;
}
#Entity
class Tag {
#Id
private Long id;
private String name;
}
In PostRepository I want to have 2 methods, which:
find all posts that contain at least one (or more) of specified tags.
find all posts that contain all specified tags.
Something like:
List<Post> findByTagsContainsAnyOf(List<String> tags);
List<Post> findByTagsContainsAll(List<String> tags);
The first one is easy - List<Post> findByTagsIn(List<Tag> tags). Note that it is List<Tag> instead of List<String> since it is Tag that is mapped to Post and not String. If you want to stick to List<String>, you will have to use a #Query. Something like #Query("SELECT p FROM Post p WHERE p.tags CONTAINS (SELECT t FROM Tag t WHERE t.name IN :tags)") should work.
The second one will have to be done through a #Query by putting a join between the Post and Tag entities.
In general, JPA is merely an object-oriented API over SQL. So, when in doubt, create the SQL and then convert it into the equivalent JPQL. Where the JPQL is straightforward, it can be coded as the method name, relying on the Spring Data query creation framework to generate the JPQL from the method name.

Hibernate inheritance without table for basic entity

I've never used inheritance in hibernate and I don't know which strategy should I use (or even do I really need to use strategy). I have three tables with the same interface (the same columns) and I want to create three entities with basic interface for them so it will look like this:
#Entity
+ Basic
+ #Entity
#Table(name="TABLE_1")
Table1
+ #Entity
#Table(name="TABLE_2")
Table2
+ #Entity
#Table(name="TABLE_3")
Table3
As you see I don't want to use table for basic entity. If it is possible to do this kind of inheritance, how to do it? Maybe I don't need 'hibernate' inheritance and I should use normal inheritance?
In application it is used like this:
Somewhere in configuration we store information which entity to use (Table1, Table12 or Table3)
Choosen entity is used in our queries (some writen in HQL, some in Criteria) so each query should know which entity to use.
EDIT
What's more each entity can be used as attribute of some entities and we wan't to know which table should be used. For example:
#Entity
#Table(name="USER")
class User {
#Id
private Integer id;
#ManyToOne
#JoinColumn(name = "SOME_ID", referencedColumnName = "ID", nullable = false)
private Basic basicEntity; // how to use proper strategy using some configuration value (eg. class static attribute or configuration value stored in db?)
}
I think this is recommended way of achieving your goal:
#MappedSuperclass
public abstract class BaseEntity {
public static final int SHARED_PAREMETER = 2;
#Column(name = "modified", columnDefinition = "TIMESTAMP DEFAULT NOW()")
protected Date modified;
//... other fields, getters and setters
}
#Entity
#Table(name = "TABLE_1")
public class Table1 {
#Id
private Integer id;
#ManyToOne
#JoinColumn(name = "SOME_ID", referencedColumnName = "ID", nullable = false)
private Table2 table2;
}
#Entity
#Table(name = "TABLE_2")
public class Table2 {
#Id
private Integer id;
}
In this case, we will have only two tables but both would have fields from BaseEntity. You can't, though, make a relation in Entity to an abstract class but in processing you're fully entitled to do something like this:
public void process(BaseEntity entity){
// processing..
}

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".