Create separate hibernate search indexes for each subclass - java

I just started playing around with hibernate search.
How can I solve the following problem.
All my java entities where inherited from a superclass:
#SuppressWarnings("rawtypes")
#MappedSuperclass
#Indexed
public abstract class BaseEntity{
private Integer id;
private Integer jpaVersion;
private Date creaDate;
private Date modDate;
private String creaUser;
private String modUser;
#Id
#Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
#GeneratedValue(strategy = GenerationType.IDENTITY)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
.....
For example I have to (there are more) subclasses:
#Entity
#Indexed
#Table(name = "BASE_PERSON", schema = "MYSCHEMA")
public class Person extends extends BaseEntity{
private String firstName;
private String lastName;
....
....
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#Column(name = "LASTNAME", nullable = false, length = 50)
#NotNull
#Size(max=50)
public String getLastName() {
return this.lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#Column(name = "FIRSTNAME", length = 50)
#Size(max=50)
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
and a second one:
#Entity
#Indexed
#Table(name = "BASE_USER", schema = "MYSCHEMA")
public class User extends extends BaseEntity{
private String userName;
....
....
#Field(index=Index.YES, analyze=Analyze.YES, store=Store.NO)
#Column(name = "USERNAME", nullable = false, length = 50)
#NotNull
#Size(max=50)
public String getUserName() {
return this.userName;
}
public void setUserName(String lastName) {
this.UserName = UserName;
}
....
After running the code for creating the whole index, I got three indexes. One more than I expected. The indexes are: BaseEntity, Person and User.
But all Persons and Useres ares stored in the index BaseEntity and not in their own index.
Is there a way to change this, so that all persons are in the index person and all users are in the index users?
Or is this the common behaviour of hibernate search?
Thanks and Regards
LStrike

You'll want to remove the #Indexed from the BaseEntity, you only need that annotation on the subclasses. You can still annotate properties in BaseEntity with #Field to make them appear in the subclass indexes.

Related

Java Spring JPA how to map my User model to Profile model by userName?

I am learning Spring and I can't find out how to map two models in Spring JPA. I was able to join table by ID. By default it links user.id. I want to link the user.userName. How to change it?
My User model:
#Entity
#Table(name = "user")
public class SiteUser {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "username", unique = true, length = 30)
private String userName;
#Column(name = "email", unique = true, length = 60)
private String email;
#Column(name = "password", length = 60)
private String password;
#Column(name = "role", length = 15)
private String role;
#Column(name = "fullname", length = 60)
private String fullName;
#Column(name = "age", length = 3)
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
My Profile model:
#Entity
#Table(name="profile")
public class Profile {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
private Long id;
#OneToOne(targetEntity=SiteUser.class)
#JoinColumn(name="user_id", nullable=false)
private SiteUser user;
#Column(name="about", length=5000)
private String about;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public SiteUser getUser() {
return user;
}
public void setUser(SiteUser user) {
this.user = user;
}
public void safeCopyFrom(Profile other){
if(other.about !=null){
this.about = other.about;
}
}
}
You are using a bidirectional #OneToOne relation between two entites and where you place your #JoinColumn indicates the owner side of relation that in your case you put it on Profile class.
Here is the great article about relationships between two entities, as it mentions
A Join Column in JPA is a column in the owner entity that refers to a key (usually a primary key) in the non-owner or inverse entity. The first thing that comes to mind after reading the above line is that JoinColumns are nothing but a Foreign Key Columns. And it is indeed the case. JPA calls them Join Columns, possibly because they are more verbose in what their actual role is, to join the two entities using a common column.
So you are defining a Foreing Key Column on Profile class
The rule of Foreing Key Column is that it should point to a Primary Key or a Unique Column in target entity and you should use it like this on you senario
public class Profile {
#OneToOne
#JoinColumn(name="username")
private SiteUser user;
}

OneToMany between 2 classes with Hibernate

I'm trying to get the hang of Hibernate.
After getting my project to compile, I've started to convert my classes to be "Hibernate-enabled"
Currently, I'm having 2 classes
1) Person (id, name, firstname, ...)
2) Task (Id, name, description, idOwner)
I would like to have a OneToMany relationship between Person(id) and Task (idOwner)
So when the users gets the List from the Person class, they would get all the tasks linked to that.
After some trying and failing, here's my current code:
Person.java
#Entity
#Table(name = "people", uniqueConstraints = {
#UniqueConstraint(columnNames = "PERSON_ID")
})
public class Person implements Serializable {
private int id;
private String firstName;
private String name;
private String function;
private String email;
private String password;
private RoleEnum role;
private List<Task> lstTasks;
public Person(String firstName, String name, String function) {
this.firstName = firstName;
this.name = name;
this.function = function;
this.email = "";
this.password = "";
this.setRole(RoleEnum.User);
}
// <editor-fold defaultstate="collapsed" desc="Getters">
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "PERSON_ID", unique = true, nullable = false)
public int getId() {
return id;
}
#Column(name = "PERSON_FIRSTNAME", unique = false, nullable = false, length = 30)
public String getFirstName() {
return firstName;
}
#Column(name = "PERSON_NAME", unique = false, nullable = false, length = 30)
public String getName() {
return name;
}
#Column(name = "PERSON_FUNCTION", unique = false, nullable = false, length = 30)
public String getFunction() {
return function;
}
#Column(name = "PERSON_EMAIL", unique = false, nullable = false, length = 30)
public String getEmail() {
return email;
}
#Column(name = "PERSON_PASSWORD", unique = false, nullable = false, length = 30)
public String getPassword() {
return password;
}
#Column(name = "PERSON_ROLE", unique = false, nullable = false, length = 30)
public RoleEnum getRole() {
return role;
}
#OneToMany(fetch = FetchType.LAZY, mappedBy = "idOwner")
public List<Task> getLstTasks() {
return lstTasks;
}
//Setters
}
Task.java
#Entity
#Table(name="tasks", uniqueConstraints =
#UniqueConstraint(columnNames = "TASK_ID"))
public class Task implements Serializable {
private int id;
private String name;
private String description;
private int idOwner;
public Task(int id, String name, int idOwner) {
this.id = id;
this.name = name;
this.idOwner = idOwner;
}
// <editor-fold defaultstate="collapsed" desc="Getters">
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "TASK_ID", unique = true, nullable = false)
public int getId() {
return id;
}
#Column(name = "TASK_NAME")
public String getName() {
return name;
}
#Column(name = "TASK_DESCRIPTION")
public String getDescription() {
return description;
}
#Column(name = "TASK_ID_OWNER")
public int getIdOwner() {
return idOwner;
}
// </editor-fold>
//Setters
}
Can somebody tell/show/explain me what I have to do exactly, to make this work?
Currently your mapping should linking ownerId instead of Task class.
Change your Task class to this
private Person person;
#ManyToOne
#JoinColumn(name = "TASK_ID_OWNER")
public Person getPerson() {
return person;
}
In your Person entity you have declared one-to-many relationship with Task entity like this:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "idOwner")
public List<Task> getLstTasks() {
return lstTasks;
}
Here you have given idOwner to mappedBy attribute, it means you are telling hibernate that there is property in Task class called idOwner which is of type Person.
So you have to modify your Tasks class like this (Changing the variable type from int to Person):
private Person idOwner;
#ManyToOne
#JoinColumn(name = "TASK_ID_OWNER")
public Person getIdOwner() {
return idOwner;
}
public void setIdOwner(Person idOwner) {
this.idOwner=idOwner;
}
If you remove the #JoinColumn annotation then hibernate will create a Join table for your relationship, else it will just create a foreign key in Task table with foreign key column name as TASK_ID_OWNER.

Saving the foreign key in a hibernate

I have two tables 1. User 2. USersLocation, In the location table I use the userId as foreign key. When I save the location object in database I want to save the current user Id as well in the table.
What I have tried so far is
SocialLogin Controller
SocialAuthManager manager = socialAuthTemplate.getSocialAuthManager();
AuthProvider provider = manager.getCurrentAuthProvider();
Profile userProfile = provider.getUserProfile();
Location Controller
UsersLocation location = new UsersLocation();
location.setSourceLat(SOURCE_LATITUDE);
location.setSourceLng(SOURCE_LONGITUDE);
location.setDestinationLat(DEST_LATITUDE);
location.setDestinationLng(DEST_LONGITUDE);
location.setUserId((User) WebUtils.getSessionAttribute(request, "userId"));
placesService.saveLocaion(location);
The Userslocation class is
#Entity
#Table(name = "locations")
public class UsersLocation implements Serializable{
private static final long serialVersionUID = 1L;
private double sourceLat;
private double sourceLng;
private double destinationLat;
private double destinationLng;
public UsersLocation(){}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int locationId;
#ManyToOne
#JoinColumn(name = "userId")
private User user;
public void setUserId(User user){
this.user = user;
}
public User getUserId(){
return user;
}
#Column(name = "SourceLat", nullable = false)
public double getSourceLat(){
return sourceLat;
}
public void setSourceLat(double sourceLat){
this.sourceLat = sourceLat;
}
#Column(name = "SourceLng", nullable = false)
public double getSourceLng(){
return sourceLng;
}
public void setSourceLng(double sourceLng){
this.sourceLng = sourceLng;
}
#Column(name = "DestinationLat", nullable = false)
public double getDestinationLat(){
return destinationLat;
}
public void setDestinationLat(double destinationLat){
this.destinationLat = destinationLat;
}
#Column(name = "DestinationLng", nullable = false)
public double getDestinationLng(){
return destinationLng;
}
public void setDestinationLng(double destinationLng){
this.destinationLng = destinationLng;
}
}
User Class
#Entity
#Table(name = "users")
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer userId;
private String email;
private String lastName;
private String firstName;
private String location;
public User() {
}
#Id
#Column(name = "userId", unique = true, nullable = false)
public Integer getUserId() {
return this.userId;
}
public Integer setUserId(Integer socialId) {
return this.userId = socialId;
}
#Column(name = "email", nullable = false, length = 50)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
#Column(name = "firstName", nullable = true, length = 20)
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Column(name = "lastName", nullable = true, length = 20)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
#Column(name = "location", nullable = true, length = 50)
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
}
When I save the location I get the userId NULL,I am new to hibernate kindly help me
Thanks
Save the whole user object to the session like below instead of just the userId, as later you need to set the full User object in location.setUserId(user);
WebUtils.setSessionAttribute(request, "userId", user)
If you're saying that you want to save a Location in the database along with the UserId, you have this relation wrong. This should be a OneToOne, since each location will have only one UserId associated.
On the other hand, if you're trying to set a location capable of storing many userIds, you're also doing it wrong because you should be saving a set of users, something like:
#OneToMany(mappedBy = "UsersLocation")
private Set<User> user;
It's not really clear what you're trying to do, but I'm pretty sure your mistake lies in the fact that you're doing the relations in the wrong way.

Creating a simple user/group model with permissions with Hibernate (annotations)

This is most likely a very basic question, but nevertheless:
Basically the User entity has an Id and a privilege enum.
The group has an id and a name.
I wonder how to model a relationship where an user can be in multiple groups, having different privilege levels in different groups. Every group can of course have multiple members.
What's the way I'm supposed to solve that idiomatically with Hibernate?
Adding some membership field to User? A membership field to Group? Both? Creating a new class for it? Which annotations are required to wire these things together?
I used next architecture
UserEntity class
#Entity
#Table(name = "user")
public class UserEntity implements Serializable {
private Long user_id;
private String username;
private String password;
public UserEntity() {
}
public UserEntity(String name, String passwd) {
username = name;
password = passwd;
}
#Column(name = "password", nullable = false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
#Column(name = "username", nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
AuthorityEntity class
#Entity
#Table(name = "authority_role")
public class AuthorityEntity implements Serializable {
private Integer id;
private String authority;
private List<UserEntity> people;
public AuthorityEntity() {
}
public AuthorityEntity(String authString) {
authority = authString;
}
#Column(name = "authority", nullable = false)
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToMany(targetEntity = UserEntity.class,
cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name = "authority_role_people",
joinColumns =
#JoinColumn(name = "authority_role_id"),
inverseJoinColumns =
#JoinColumn(name = "user_id"))
public List<UserEntity> getPeople() {
return people;
}
public void setPeople(List<UserEntity> people) {
this.people = people;
}
}
In fact - this is how implemented spring security plugin.
In your case you can implement that architecture, which will be more useful for you.

how to solve lazyinitializationexception not using fetch=FetchType.EAGER?

Iam still getting the exception lazyinitializationexception.
Yes, i know that it means, that the session is closed while I or something else is trying to access the collection.
No, the OpenEntityManagerInViewFilter did not work.
Yes, #ManyToOne(fetch=FetchType.EAGER) helped but i dont want to use it, cause it will fecth aumotically all the time.
How Else can i do that ?
P.S. : I am using HibernateEntityManger with jpa with annotated class.
UPADATE
here is my code, first of all
I have 4 tables :
users(id,first_name,last_name,email....)
roles(id,name,comment....)
users_roles(user_id,role_id)
mails(id,user_id,subject,message,to_id...)
An user can have mutiples roles ....
Users Entity
#Entity
#Table(name = "USERS")
public class User implements GenericDomain{
public static final String _ID = "id";
private Long id;
private String firstName;
private String lastName;
private String email;
private Set<Role> roles = new HashSet<Role>(0);
/* Constructors */
public User() {
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "ID", unique = true, nullable = false)
public Long getId() { return this.id; }
public void setId(Long id) { this.id = id; }
#Column(name="FIRST_NAME", nullable = false, length = 64)
#NotEmpty
#Length(min = 4, max = 45)
public String getFirstName() { return this.firstName; }
public void setFirstName(String firstname) { this.firstName = firstname; }
#Column(name="LAST_NAME", nullable = false, length = 64)
#NotEmpty
#Length(min = 4, max = 45)
public String getLastName() { return this.lastName; }
public void setLastName(String lastname) { this.lastName = lastname; }
#Column(name="EMAIL", unique = false, length = 64)
#Email
#NotEmpty
#Length(min = 4, max = 45)
public String getEmail() { return this.email; }
public void setEmail(String email) { this.email = email; }
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name = "USERS_ROLES"
, joinColumns = { #JoinColumn(name = "user_id") }
, inverseJoinColumns = { #JoinColumn(name = "role_id") }
)
public Set<Role> getRoles() {
return this.roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
/*#Override toString/equals/hascode */
}
Role Entity
#Entity
#Table(name = "ROLES")
public class Role implements GenericDomain {
private Long id;
private String name;
private String comment;
private Set<User> users = new HashSet<User>(0);
public Role() {
}
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name = "ID", unique = true, nullable = false)
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
#Column(name="NAME", nullable = false, length = 64)
#NotEmpty
#Length(min = 1, max = 32)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#Column(name="COMMENT", nullable = true, length = 256)
#Length(min = 0, max = 255)
public String getComment() { return this.comment; }
public void setComment(String comment) { this.comment = comment;}
#ManyToMany(cascade=CascadeType.REFRESH,fetch=FetchType.EAGER)
#JoinTable(
name = "USERS_ROLES"
, joinColumns = { #JoinColumn(name = "role_id") }
, inverseJoinColumns = { #JoinColumn(name = "user_id") }
)
public Set<User> getUsers() {
return this.users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
/*#Override toString/equals/hascode */
}
mails
#Entity
#Table(name = "mails")
public class Mail implements GenericDomain{
private Long id;
private String mailSubject;
private String mailContent;
private Long receiverId;
private User user = null;
public Mail(){
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID", nullable = false)
public Long getId(){ return this.id; }
public void setId(Long id){ this.id = id;}
#Column(name = "MAILSUBJECT", nullable = false, length = 63)
#Length(max = 63)
public String getMailSubject(){ return this.mailSubject; }
public void setMailSubject(String mailSubject){ this.mailSubject = mailSubject; }
#Column(name = "MAILCONTENT", nullable = true, length = 255)
#Length(max = 255)
public String getMailContent(){ return this.mailContent; }
public void setMailContent(String mailContent){ this.mailContent = mailContent; }
#Column(name = "RECEIVERID")
public Long getReceiverId(){ return this.receiverId; }
public void setReceiverId(Long receiverId){ this.receiverId = receiverId; }
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "USER_ID")
#NotNull
public User getUser(){ return this.user; }
public void setUser(User user){ this.user = user; }
}
user controller
#Controller
#RequestMapping("/admin/user")
#SessionAttributes("user")
public class UserController {
private UserService userService;
private RoleService roleService;
#Autowired
public UserController(UserService userService, RoleService roleService) {
this.userService = userService;
this.roleService = roleService;
}
#RequestMapping(value = "edit", method = RequestMethod.GET)
public String editUser(#RequestParam(value="id", required = true) Long id, ModelMap model) {
model.addAttribute("allRoles", roleService.getAll());
model.addAttribute("user", userService.getOne(id));
return "/admin/user/edit";
} }
mail controller
#Controller
#SessionAttributes("mail")
#RequestMapping("/portal/mail")
public class MailController{
#Autowired
private MailService mailService;
#RequestMapping(value = "ajaxLoad", method = RequestMethod.GET)
public #ResponseBody List<Mail> list(#RequestParam(value = "type", required = true) String type){
return mailService.getUserMails((Long) WebHelper.getPrincipal().getUser().getId(),type);
}
}
my web.xml
<filter>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
my edit.jsp for user
<select >
<c:forEach items="${allRoles}" var="role">
<option value="${role.id}" <c:if test="${fn:contains(roleSelected, role)}">selected="selected"</c:if> >${role.name}</option>
</c:forEach>
</select>
With all that, i edit.jsp for user is working fine with lazy=false.
With FetchType.EAGER am not able to get any of my mails, am getting into a cycle stackovrflow, without FetchType.EAGER i got that lazy exception.
removing all the eager and adding this solve my problem
<mvc:interceptors>
<bean class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
</mvc:interceptors>
the filter didnt work
OpenEntityManagerInViewFilter and OpenEntityManagerInViewInterceptor work. You are doing something wrong.
Apart from that, you can use Hibernate.initialize(..) to initialize your collections. But doing this manually is not preferred. Give more details of why the filter/interceptor don't work.
Update: Instead of mapping the filter to a pattern, map it to the dispatcher servlet. So instead of specifying <url-pattern> specfiy <servlet-name>.
First of all, check if you really need Collection rather than Set. If objects within collection are unique, declare variable as Set, which solves 90% of issues with LazyInitializationException.

Categories