I have an entity User and System
#Entity
public class User {
private Long id;
private String name;
}
#Entity
public class System{
private Long id;
private Long SystemId;
#ManyToMany
private Set<User> users;
}
and one table created by hibernate legalhold_system
I want to get all the user related to System ID, I can fetch the same using below native query
select * from user where id in (select user_id from legalhold_system where system_id in(select id from system_user where system_id=:1))
How can I achieve the same with Spring JPA query, As I don't have legalhold_system entity present in Code?
If these are the only two entities, it should be doable using this query:
SELECT s.users FROM System s WHERE s.systemId = :systemId
Related
I am trying to retrieve some rows from my DB, like
select * from my_table where id between 1 and 100;
Is there any option in JpaRepository for between on primary key?
Any custom method can be written in JPARepo. You need to make sure you are following JPA rules. The field name should exist in the method, In bellow method Id is my field name in my Entity class.
Entity Class
#Entity
#Setter#Getter
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
}
Repo Class
#Repository
public interface CourseSprngDataRepo extends JpaRepository<Course, Long>{
List<Course> findByIdBetween(Long l, Long m);
List<Course> findByIdBetweenOrderByNameAsc(long l, long m);//Between and Order by another column ex
}
I'm trying to build the relationship between two tables using spring-data jpa. I have read many SO articles like 1, 2 but they are pretty old and don't seem to apply to my specific use case. Hence this question:
There are 2 tables user_client_scopes and scopes listed below.
user_client_scopes:
user_id (long),
client_id (string)
last_updated (timestamp)
scope_id (Foreign key to scopes table),
primary key (user_id, client_id, scope_id)
scopes:
id (int, primary key)
name (string)
A <user_id, client_id> can have multiple scopes. Similarly, the same scope can be held by many <user_id, client_id>s. Hence the many-to-many relationship. The join table (as defined by spring-data-jpa) is kind of embedded within user_client_scope table.
Here is a half-written-code:
#Entity
#Table(name = "user_client_scopes")
#RequiredArgsConstructor
#IdClass(UserClientScopesPK.class)
public class UserClientScopes implements Serializable {
#Id
#Column(name = "user_id")
private long userId;
#Id
#Column(name = "client_id")
private String clientId;
#Column(name = "last_updated")
private Timestamp lastUpdated;
#Id
#Column(name = "scope_id")
private int scopeId;
#ManyToMany // <- how to complete this definition?
private Set<Scope> scopes;
getters and setters.
Here are 2 other classes (for the sake of completion).
#Data
#RequiredArgsConstructor
public class UserClientScopesPK implements Serializable {
private long userId;
private String clientId;
private int scopeId;
}
#Entity
#Table(name = "scopes")
#RequiredArgsConstructor
public class Scope implements Serializable {
#Id
#GeneratedValue
private long id;
private String name;
}
How do I complete the user_client_scopes entity such that we can:
Find all scopes for a given <user_id, client_id>. i.e. execute the following SQL:
select user_id, client_id, scope
from scopes
join user_client_scopes ucs on ucs.scope_id = scopes.id
where ucs.user_id = ? and ucs.client_id = ?
Save new scopes for a given <user_id, client_id>. i.e. execute the following SQL:
insert into user_client_scopes (user_id, client_id, scope_id, last_updated)
select ?, ?, id, now()
from scopes
where scopes.name = ?
UPDATE 1:
Changing title to Many to one instead of Many to many relationship.
That's not a many-to-many because the association scope is mapped by the column scope_id in user_client_scopes. This means that if I take a single row in the table user_client_scopes, it will be associated to only a single row in the table scopes. Therefore, this is a many-to-one.
If the three columns <user_id, client_id, scope_id> form the key for user_client_scopes, then the mapping for the table should look like:
Entity
#Table(name = "user_client_scopes")
#RequiredArgsConstructor
#IdClass(UserClientScopesPK.class)
public class UserClientScopes implements Serializable {
#Id
#Column(name = "user_id")
private long userId;
#Id
#Column(name = "client_id")
private String clientId;
#Column(name = "last_updated")
private Timestamp lastUpdated;
#Id
#ManyToOne
#JoinedColumn(name = "scope_id")
private Scope scope;
getters and setters.
}
class UserClientScopesPK implements Serializable {
private long userId;
private String clientId;
private Scope scope;
// getters,setters, equals and hascode
}
With this mapping you can run the following HQL:
select ucs
from UserClientScopes ucs join ucs.scope
where ucs.userId = :userId and ucs.clientId = :clientId
It will return all UserClientScopes entities matching the selected pair <userId, clientId>. Each one with a different scope.
Or, if you only care about the scope:
select s
from UserClientScopes ucs join ucs.scope s
where ucs.userId = :userId and ucs.clientId = :clientId
With Spring Data JPA, it will look like this:
#Query("select s from UserClientScopes ucs join ucs.scope swhere ucs.userId = ?1 and ucs.clientId = ?2")
public List<Scope> findScopesByUserIdAndClientId(long userId, String clientId);
or
#Query("select s.name from UserClientScopes ucs join ucs.scope swhere ucs.userId = ?1 and ucs.clientId = ?2")
public List<String> findScopesNameByUserIdAndClientId(long userId, String clientId);
You can also run the insert query as native SQL (you can probably run something similar as HQL, but I don't remember the right syntax now. I will update the answer later).
One last thing, to keep track of the last updated time, you could use Spring Entity callback listener:
#Entity
...
#EntityListeners(AuditingEntityListener.class)
public class UserClientScopes implements Serializable {
#LastModifiedDate
#Column(name = "last_updated")
private Date lastUpdated;
}
I have created two entities Book and Book_Category with one-to-many relationship. When I issued BookCategoryRepository.findAll(), I expected hibernate to use 'INNER JOIN' query. But it just issued query to take data from Book_Category.
What I am missing? What should I do to make hibernate issue JOIN query?
Book.java
#Entity
public class Book {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#ManyToOne
#JoinColumn(name = "book_category_id")
private BookCategory bookCategory;
}
BookCategory.java
#Entity
#Table(name = "book_category")
public class BookCategory {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
#OneToMany(mappedBy = "bookCategory", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Book> books;
}
BookCategoryRepository.java
public interface BookCategoryRepository extends JpaRepository<BookCategory, Integer> {
}
bookCategoryRepository.findAll()
Hibernate uses by default a second query to retriev the child collection. One reason for this is a proper limit query. Otherwise, there would be more rows in the result set, than entities for the 1 side, if at least one has more than 1 child.
There exists an annotation to change this behaviour in hibernate which is ignored by the Spring Data Jpa Repositories. The annotation is #Fetch(FetchMode.JOIN). You might consider How does the FetchMode work in Spring Data JPA if you really need this behaviour.
I am using an #Entity with a CrudRepository to create an entry in my MySQL database, and I was wondering at what point the #GeneratedValue(strategy = GenerationType.AUTO) execute and generate the auto increment value?
#Entity
#Table(name = "all_contacts")
public class Contact {
//Ideally this would be set as foreign key to application's user schema
private long userId;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column( name="contactid")
private long contactId;
#NotNull
private String name;
//getters and setters
}
//
public interface ContactRepository extends CrudRepository<Contact, Long> { }
I ask because I want to access the value of the contactId through its getter, but do I have to wait until the ContactRepository.save() is called?
We can't know the new assigned id of that entity prior to executing the SQL INSERT statement.
So, yes you need to ContactRepository.save() or any command that trigger SQL INSERT statement before can get that id. But save is better because it is guaranteed that it will always return ID.
We get the generated value once SQL insert statement is executed. We can't know the value is being assinged before save(). GenerationType.AUTO number generator generates automatic object IDs for entity objects and this generated numeric value is used for primary key field.
#Entity
public class Entity {
#Id #GeneratedValue(strategy=GenerationType.AUTO) int id;
}
I have two entity bean :
#Entity
public class User {
#Id
#GeneratedValue
private Long id;
#OneToMany(mappedBy="user", cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<Comment>();
//SOME OTHER CLASS VARIABLES
//GETTERS AND SETTERS
}
and my Comment class is like this :
#Entity
public class Comment {
#Id
#GeneratedValue
private Long id;
private String title;
private String content;
#ManyToOne
private User user
//SOME OTHER CLASS VARIABLES
//GETTERS AND SETTERS
}
now I know that I can get the User Object from session and set the user for my comment like this in order to be able to use the join feature in JPA:
commentObject.setUser(TheSessionGrabedUserObject/UserObjectWhichHasFetchedFromDbUsingUserId);
but as long as I have the userId for my user Object I do not need to do this.
I'm looking for a way to insert this foreignKey into my comment table without getting the User Object from session or maybe query to database to fetch it first !
how I'm gonna do it using JPQL ?
You can use the entityManager.getReference() method. In your case:
entityManager.getReference(User.class, userId);
This will not perform any DB query, but will give you a User instance with only the ID populated, and you can pass that to commentObject.setUser().