Spring : How to delete entry from junction table? - java

I have a junction table of user_id and favorite_property_id And now I want to delete the favorite property of the user , I tried the following method in repository but its not working , Does anybody have any idea that how can i delete he entry from junction table?
User.java
#Entity
public class User implements Serializable, UserGetters {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToMany(fetch = FetchType.EAGER)
private Set<Property> favouriteProperty;
public Set<Property> getFavouriteProperty() {
return favouriteProperty;
}
public void setFavouriteProperty(Set<Property> favouriteProperty) {
this.favouriteProperty = favouriteProperty;
}
}
UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
//#Transactional
// Long deleteByFavouritePropertyId(#Param("favoriteProperty") Long favoriteProperty);
// #Query("delete favouriteProperty from user u where u.favouriteProperty.id=:favouriteProperty")
// void unmarkFavouriteProperty(#Param("favouriteProperty") Long favouriteProperty);
}

You can do it like:
1. Load user object
User user = userRepository.findOne(userId);
2. Remove required object from list
user.getFavouriteProperty().remove(id);
3. Save User Object
userRepository.save(user);

Try using :
Query query = session.createQuery("delete Category where id = :favorite_property_id ");
query.setParameter("favorite_property_id ", new Long(favoriteProperty));
int result = query.executeUpdate();
in your repository file. It will work fine.

This was so simple :P
I can delete by using following API
API : http://localhost:8555/api/users/2/favouriteProperty/3
METHOD : DELETE

Related

How to get Field Variable on Java Spring

I has a issue on my learn project, on case "if condition value is null and then else if condition value field is null" for example my code following these code :
For Entity Users.java :
#Entity
public class Users {
private Long id;
private String employeeId;
private String fullName;
private String username;
private String password;
...
public Users() {
}
Some Code Setter and Getter....
}
For Entity Employee.java :
#Entity
public Class Employee {
private Long id;
private String employeeId;
private String fullName;
...
public Employee() {
}
Some Code Setter and Getter....
}
and then for my Class Service i have case for insert data Employee with Repository. On case we have validation data before insert data to table Employee, we need to check table users not null and then on field employeeId should null. with my code following this :
For Repository UserRepo.java and EmployeeRepo.java :
#Repository
public interface EmployeeRepo extends CrudRepository<Employee, Long> {
}
#Repository
public interdace UsersRepo extends CrudRepository<Users, Long> {
#Transactional
#Modifying(clearAutomatically = true, flushAutomatically = true)
#Query("UPDATE Users u SET u.employeeId = :employeeId WHERE u.id = :id")
public void updateEmployeeIdUsers(#Param("id") Long id, #Param("employeeId") String employeeId);
}
For Service UsersService.java :
#Service("usersService")
public class UsersService {
#Autowired
private UsersRepo repo;
public Optional<Users> findById(Long id) {
return repo.findById(id);
}
public void updateEmployeeIdUsers(Long id, String employeeId) {
repo.updateEmployeeIdUsers(id, employeeId);
}
}
For Service EmployeeService.java :
#Service("employeeService")
public class EmployeeService {
#Autowired
private EmployeeRepo employeeRepo;
#Autowired
private UsersService userService;
public Employee insertEmployee(Employee employee) throws Exception {
Optional<Users> users = userService.findById(employee.getId());
Users userOptional = new Users(); **//on this my problem**
userOptional.getEmployeeId(); **//on this my problem**
if (!users.isPresent()) {
throw new Exception("User ID : "+ employee.getId() +" Not Founded");
}else if (!(userOptional == null)) { **//on this my problem**
throw new Exception("User employeID : "+ employee.getEmployeeId() +" Already Exist on Users");
}
String str1 = "TEST";
Long idUser = employee.getId();
userService.updateEmployeeIdUsers(idUser, str1);
return employeeRepo.save(employee);
}
}
on this code we have problem on else if userOptional is always NULL and i try to debug to see value on employeeId just i see always Null. so any idea with my problem because i try some case alway fail with my issue. please if any idea for my issue, can reply these my question. is very thank you of all about thing to answer my question.
For the proposed solution, I will assume the following:
There is relation between Employee and Users.
An Employee can be related with only one Users
username is the natural key of Users
employeeId is the natural key of Employee
So the entities:
#Entity
public class Users {
#Id
// This one is an example, you can use the configuration you need
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator= "users_seq")
#SequenceGenerator(name="users_seq", initialValue=1, allocationSize=1, sequenceName = "users_id_seq")
private Long id;
#Column(name = "fullname")
private String fullName;
// Probably this column should be unique and you need to configure in that way here and in your database
#Column
private String username;
#Column
private String password;
// Getter & setter & constructors
}
#Entity
public class Employee {
#Id
// This one is an example, you can use the configuration you need
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator= "employee_seq")
#SequenceGenerator(name="employee_seq", initialValue=1, allocationSize=1, sequenceName = "employee_id_seq")
private Long id;
/**
* Assuming this is your specific identifier for an employee (not related with database PK)
* If the assumption is correct, this column should be unique and you need to configure in
* that way here and in your database
*/
#Column(name = "employeeid")
private String employeeId;
/**
* Not sure if this relation could be nullable or not
*/
#OneToOne
#JoinColumn(name = "users_id")
private Users users;
// Getter & setter & constructors
}
As you can see, there are no "repeated columns" in both entities and there is an unidirectional OneToOne relation between Employee and Users. If you need a bidirectional one, this link will help you with it: Bidirectional OneToOne
The repositories:
#Repository
public interface UsersRepository extends CrudRepository<Users, Long> {
Optional<Users> findByUsername(String username);
}
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, Long> {
Optional<Employee> findByEmployeeId(String employeeId);
}
The services:
#Service
public class UsersService {
#Autowired
private UsersRepository repository;
public Optional<Users> findByUsername(String username) {
return Optional.ofNullable(username)
.flatMap(repository::findByUsername);
}
public Optional<Users> save(Users user) {
return Optional.ofNullable(user)
.map(repository::save);
}
}
#Service
public class EmployeeService {
#Autowired
private EmployeeRepository repository;
#Autowired
private UsersService usersService;
public Optional<Employee> insert(Employee newEmployee) {
/**
* The next line don't make sense:
*
* Optional<Users> users = userService.findById(employee.getId());
*
* I mean:
*
* 1. Usually, id column is configured with #GeneratedValue and manage by database. So you don't need to ask
* if that value exists or not in Users.
*
* 2. Even if you are including id's values manually in both entities what should be "asked" is:
*
* 2.1 Is there any Users in database with the same username than newEmployee.users.username
* 2.2 Is there any Employee in database with the same employeeId
*
* Both ones, are the natural keys of your entities (and tables in database).
*/
return Optional.ofNullable(newEmployee)
.filter(newEmp -> null != newEmp.getUsers())
.map(newEmp -> {
isNewEmployeeValid(newEmp);
// Required because newEmp.getUsers() is a new entity (taking into account the OneToOne relation)
usersService.save(newEmp.getUsers());
repository.save(newEmp);
return newEmp;
});
}
private void isNewEmployeeValid(Employee newEmployee) {
if (usersService.findByUsername(newEmployee.getUsers().getUsername()).isPresent()) {
throw new RuntimeException("Username: "+ newEmployee.getUsers().getUsername() +" exists in database");
}
if (repository.findByEmployeeId(newEmployee.getEmployeeId()).isPresent()) {
throw new RuntimeException("EmployeeId: "+ newEmployee.getEmployeeId() +" exists in database");
}
}
}
After read comments I already understand your problem.
Users users = userService.findById(employee.getId()).orElseThrow(() -> new Exception("User ID : "+ employee.getId() +" Not Founded"));
And now you can get your employeeId from users from returned userService.findById(employee.getId());
Example:
String employeeId = users.getEmployeeId(); // reference to your code
But in this case in my opinion you should make relation #OneToOne between users and employee or extend users in employee class.
One-To-One relation in JPA,
hibernate-inheritance

Is it possible to replace or modify values from projections or anonymous classes?

In my application I am using projections to map *Entity objects to simplified or modified versions of the actual record in the database.
However, I have a particular use case where I am required to replace a certain value from one of the nested projections. Since these are interfaces and also get proxied by Spring, I am not sure if what I want is actually possible but to bring it down to one very simpel example:
Assume I have a UserEntity and a User projection. For my User projection I can simply execute:
User user = this.userEntityRepository.findById(userId);
However, if I want to change something, I am not sure if that is possible. Namely, I cannot do something like this:
if (user.getAge() < 18) {
user.setDisplayName(null);
}
Now, I am aware that I could create an anonymous class new User() { .. } and just pass in the values I required but in my case the objects are nested and hence this is not an option.
The question
Is there another way to replace a value, e.g. displayName as above, without using an anonymous class?
Elaborative example
Reading the following is not really necessary but in order to illustrate my issue in more detail I have pseudo-coded an example that shows a bit closer what the problem is in my particular case.
We have a simple UserEntity:
#Entity
#Table(name = "app_user")
public class UserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column
private String firstName;
#Column
private String lastName;
#Column
private Integer age;
// Setter & Getter ..
}
#Entity
#Table(name = "event")
public class EventEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "event")
private List<EventAttendeeEntity> attendees;
// ..
}
We have a table which maps users to events:
#Entity
#Table(name = "attendee")
public class AttendeeEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private EventEntity event;
#ManyToOne
private UserEntity user;
// ..
}
Further, we have projections for these entities which we prepare as views for our clients:
/*
* Projection for User
*/
public interface User {
// All the properties ..
}
/*
* Projection for AttendeeEntity
*/
public interface Attendee {
Long getId();
User getUser();
}
/*
* Projection for EventEntity
*/
public interface Event {
Long getId();
String getName();
List<Attendee> getAttendees();
}
In one of the services we fetch UserEvent. Here, let's say, we want to remove the names of all users below 18 and still return userEvent we just fetched.
public Event getEvent(Long id, Boolean anonymize) {
Event event = this.eventRepository.findById(id);
// The "anonymize" is to highlight that I cannot
// simply solve this in a User-projection
if (!anonymize) {
return event;
}
event
.getAttendees();
.stream()
.peek(attendee -> {
User user = attendee.getUser();
if(user.getAge() < 18) {
// Here we create a new user object without a name
User newUser = new User() {
#Override
String getDisplayName() { return null; }
#Override
Integer getAge() { return user.getAge(); }
}
// !! This is where we hit the problem since we cannot
// !! replace the old user object like this
attendee.setUser(newUser);
}
});
return event;
}
One solution is to use SPEL in you projection selector. Please try
public interface Attendee {
Long getId();
#Value("#{target.user.age >= 18 ? target.user : new your.package.UserEntity()}")
User getUser();
}
Replace you.package with the package of UserEntity. Pay attention to put new UserEntity() and not new User(). This way an empty model will be projected as an empty interface User.
You can't use projections to update your code.
As a final note, it's important to remember that projections and excerpts are meant for the read-only purpose.
API Data Rest Projections Baeldung

Spring Data JPA + Hibernate way to set transient field without hitting db for each entity, without loading onetomany collection

I have two entities, simplified for the case. The isActive field changes with current time so i did not want to store it in db.
Condition of isactive:
isActive = 1 if (current_timestamp between userstatus.datebegin and userstatus.dateend) else isActive = 0
What I want:
I want to get a set of ALL users, with their isActive values set without hitting to the db for every user and preferably; without userStatus collection carried around. Is there a way to satify this programmatically or jpa way? Or what is the best way to achieve this?
User.java:
#Entity
public class User {
#Id
private long id;
#Transient
private int isActive;
#OneToMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<UserStatus> userStatus = new HashSet<>();
}
UserStatus.java:
public class UserStatus {
#Id
private long id;
#Column
private Date dateBegin;
#Column
private Date dateEnd;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name= "user_tr_id_no")
private UmutUser user;
}
UserRepository.java:
#Repository
public interface UserRepository extends JpaRepository<User, long> {
Set<User> findAllFetchWithIsActive();
}
Ways I tried:
*Way1: PostLoad
Problem: If I dont fetch userStatus, it hits the db for every user object.
*Way2: JPQL Query:
Problem: Couldnt find a query to set transient value except something suggested in here. The problem is it hits the db for every user object again.
*Way3: Eagerly fetch userStatus, calculate isActive values in service, hide the set of userstatus in a DTO before passing around.
Problem: This is my last resort, I have doubts fetching userStatus set for ALL users is a good approach.
I think the best approach would be something like this:
#Query("SELECT e FROM User u WHERE u.userStatus.dateBegin < CURRENT_DATE AND u.userStatus.dateEnd > CURRENT_DATE")
Iterable<User> findAllActiveUsers();
And in your User class
#Entity
public class User {
#Id
private long id;
#OneToMany(mappedBy = "user",fetch = FetchType.LAZY)
private Set<UserStatus> userStatus = new HashSet<>();
#Transient
public int isActive(){
for(UserStatus status: userStatus) {
//Add your logic to check if the current date is between the range
}
}
}
You may want to use the new operator:
select new UserWithStatus(
u,
u.userStatus.dateBegin < CURRENT_DATE AND u.userStatus.dateEnd > CURRENT_DATE)
from User u
And have your object UserWithStatus:
public class UserWithStatus {
private User user;
private boolean active;
public UserWithStatus(User user, boolean active) {
this.user = user;
this.active = active;
}
}
And have this in your repository:
#Query("...")
Set<UserWithStatus> findAllFetchWithIsActive();
Note: I think this will bring you duplicate (eg: one User with several status). You might need to use a subquery and I don't know if JPQL will allow you this:
select new UserWithStatus(u,
(select count(*)
from u.userStatus w
where w.dateBegin < CURRENT_DATE
and w.dateEnd > CURRENT_DATE)) > 0
from User u

JPA: How to get entity based on field value other than ID?

In JPA (Hibernate), when we automatically generate the ID field, it is assumed that the user has no knowledge about this key. So, when obtaining the entity, user would query based on some field other than ID. How do we obtain the entity in that case (since em.find() cannot be used).
I understand we can use a query and filter the results later. But, is there a more direct way (because this is a very common problem as I understand).
It is not a "problem" as you stated it.
Hibernate has the built-in find(), but you have to build your own query in order to get a particular object. I recommend using Hibernate's Criteria :
Criteria criteria = session.createCriteria(YourClass.class);
YourObject yourObject = criteria.add(Restrictions.eq("yourField", yourFieldValue))
.uniqueResult();
This will create a criteria on your current class, adding the restriction that the column "yourField" is equal to the value yourFieldValue. uniqueResult() tells it to bring a unique result. If more objects match, you should retrive a list.
List<YourObject> list = criteria.add(Restrictions.eq("yourField", yourFieldValue)).list();
If you have any further questions, please feel free to ask. Hope this helps.
if you have repository for entity Foo and need to select all entries with exact string value boo (also works for other primitive types or entity types). Put this into your repository interface:
List<Foo> findByBoo(String boo);
if you need to order results:
List<Foo> findByBooOrderById(String boo);
See more at reference.
Basically, you should add a specific unique field. I usually use xxxUri fields.
class User {
#Id
// automatically generated
private Long id;
// globally unique id
#Column(name = "SCN", nullable = false, unique = true)
private String scn;
}
And you business method will do like this.
public User findUserByScn(#NotNull final String scn) {
CriteriaBuilder builder = manager.getCriteriaBuilder();
CriteriaQuery<User> criteria = builder.createQuery(User.class);
Root<User> from = criteria.from(User.class);
criteria.select(from);
criteria.where(builder.equal(from.get(User_.scn), scn));
TypedQuery<User> typed = manager.createQuery(criteria);
try {
return typed.getSingleResult();
} catch (final NoResultException nre) {
return null;
}
}
Best practice is using #NaturalId annotation. It can be used as the business key for some cases it is too complicated, so some fields are using as the identifier in the real world.
For example, I have user class with user id as primary key, and email is also unique field. So we can use email as our natural id
#Entity
#Table(name="user")
public class User {
#Id
#Column(name="id")
private int id;
#NaturalId
#Column(name="email")
private String email;
#Column(name="name")
private String name;
}
To get our record, just simply use 'session.byNaturalId()'
Session session = sessionFactory.getCurrentSession();
User user = session.byNaturalId(User.class)
.using("email","huchenhai#qq.com")
.load()
This solution is from Beginning Hibernate book:
Query<User> query = session.createQuery("from User u where u.scn=:scn", User.class);
query.setParameter("scn", scn);
User user = query.uniqueResult();
I solved a similar problem, where I wanted to find a book by its isbnCode not by your id(primary key).
#Entity
public class Book implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
private String isbnCode;
...
In the repository the method was created like #kamalveer singh mentioned. Note that the method name is findBy+fieldName (in my case: findByisbnCode):
#Repository
public interface BookRepository extends JpaRepository<Book, Integer> {
Book findByisbnCode(String isbnCode);
}
Then, implemented the method in the service:
#Service
public class BookService {
#Autowired
private BookRepository repo;
public Book findByIsbnCode(String isbnCode) {
Book obj = repo.findByisbnCode(isbnCode);
return obj;
}
}
Write a custom method like this:
public Object findByYourField(Class entityClass, String yourFieldValue)
{
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery(entityClass);
Root<Object> root = criteriaQuery.from(entityClass);
criteriaQuery.select(root);
ParameterExpression<String> params = criteriaBuilder.parameter(String.class);
criteriaQuery.where(criteriaBuilder.equal(root.get("yourField"), params));
TypedQuery<Object> query = entityManager.createQuery(criteriaQuery);
query.setParameter(params, yourFieldValue);
List<Object> queryResult = query.getResultList();
Object returnObject = null;
if (CollectionUtils.isNotEmpty(queryResult)) {
returnObject = queryResult.get(0);
}
return returnObject;
}
Edit: Just realized that #Chinmoy was getting at basically the same thing, but I think I may have done a better job ELI5 :)
If you're using a flavor of Spring Data to help persist / fetch things from whatever kind of Repository you've defined, you can probably have your JPA provider do this for you via some clever tricks with method names in your Repository interface class. Allow me to explain.
(As a disclaimer, I just a few moments ago did/still am figuring this out for myself.)
For example, if I am storing Tokens in my database, I might have an entity class that looks like this:
#Data // << Project Lombok convenience annotation
#Entity
public class Token {
#Id
#Column(name = "TOKEN_ID")
private String tokenId;
#Column(name = "TOKEN")
private String token;
#Column(name = "EXPIRATION")
private String expiration;
#Column(name = "SCOPE")
private String scope;
}
And I probably have a CrudRepository<K,V> interface defined like this, to give me simple CRUD operations on that Repository for free.
#Repository
// CrudRepository<{Entity Type}, {Entity Primary Key Type}>
public interface TokenRepository extends CrudRepository<Token, String> { }
And when I'm looking up one of these tokens, my purpose might be checking the expiration or scope, for example. In either of those cases, I probably don't have the tokenId handy, but rather just the value of a token field itself that I want to look up.
To do that, you can add an additional method to your TokenRepository interface in a clever way to tell your JPA provider that the value you're passing in to the method is not the tokenId, but the value of another field within the Entity class, and it should take that into account when it is generating the actual SQL that it will run against your database.
#Repository
// CrudRepository<{Entity Type}, {Entity Primary Key Type}>
public interface TokenRepository extends CrudRepository<Token, String> {
List<Token> findByToken(String token);
}
I read about this on the Spring Data R2DBC docs page, and it seems to be working so far within a SpringBoot 2.x app storing in an embedded H2 database.
No, you don't need to make criteria query it would be boilerplate code you just do simple thing if you working in Spring-boot:
in your repo declare a method name with findBy[exact field name].
Example-
if your model or document consist a string field myField and you want to find by it then your method name will be:
findBymyField(String myField);
All the answers require you to write some sort of SQL/HQL/whatever. Why? You don't have to - just use CriteriaBuilder:
Person.java:
#Entity
class Person {
#Id #GeneratedValue
private int id;
#Column(name = "name")
private String name;
#Column(name = "age")
private int age;
...
}
Dao.java:
public class Dao {
public static Person getPersonByName(String name) {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Person> cr = cb.createQuery(Person.class);
Root<Person> root = cr.from(Person.class);
cr.select(root).where(cb.equal(root.get("name"), name)); //here you pass a class field, not a table column (in this example they are called the same)
Query query = session.createQuery(cr);
query.setMaxResults(1);
List<Person> resultList = query.getResultList();
Person result = resultList.get(0);
return result;
}
}
example of use:
public static void main(String[] args) {
Person person = Dao.getPersonByName("John");
System.out.println(person.getAge()); //John's age
}
Have a look at:
JPA query language: The Java Persistence Query Language
JPA Criteria API: Using the Criteria API to Create Queries
I've written a library that helps do precisely this. It allows search by object simply by initializing only the fields you want to filter by: https://github.com/kg6zvp/GenericEntityEJB
Refer - Spring docs for query methods
We can add methods in Spring Jpa by passing diff params in methods like:
List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);
// Enabling static ORDER BY for a query
List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
In my Spring Boot app I resolved a similar type of issue like this:
#Autowired
private EntityManager entityManager;
public User findByEmail(String email) {
User user = null;
Query query = entityManager.createQuery("SELECT u FROM User u WHERE u.email=:email");
query.setParameter("email", email);
try {
user = (User) query.getSingleResult();
} catch (Exception e) {
// Handle exception
}
return user;
}
This is very basic query :
Entity : Student
#Entity
#Data
#NoArgsConstructor
public class Student{
#Id
#GeneratedValue(generator = "uuid2", strategy = GenerationType.IDENTITY)
#GenericGenerator(name = "uuid2", strategy = "uuid2")
private String id;
#Column(nullable = false)
#Version
#JsonIgnore
private Integer version;
private String studentId;
private String studentName;
private OffsetDateTime enrollDate;
}
Repository Interface : StudentRepository
#Repository
public interface StudentRepository extends JpaRepository<Student, String> {
List<Student> findByStudentName(String studentName);
List<Student> findByStudentNameOrderByEnrollDateDesc(String studentName);
#Transactional
#Modifying
void deleteByStudentName(String studentName);
}
Note:
findByColumnName : give results by criteria
List findByStudentName(String studentName)
Internally convert into query : select * from Student where name='studentName'
#Transactional
#Modifying
Is useful when you want to remove persisted data from database.
Using CrudRepository and JPA query works for me:
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
public interface TokenCrudRepository extends CrudRepository<Token, Integer> {
/**
* Finds a token by using the user as a search criteria.
* #param user
* #return A token element matching with the given user.
*/
#Query("SELECT t FROM Token t WHERE LOWER(t.user) = LOWER(:user)")
public Token find(#Param("user") String user);
}
and you invoke the find custom method like this:
public void destroyCurrentToken(String user){
AbstractApplicationContext context = getContext();
repository = context.getBean(TokenCrudRepository.class);
Token token = ((TokenCrudRepository) repository).find(user);
int idToken = token.getId();
repository.delete(idToken);
context.close();
}

Container managed security in Glassfish

I have followed this blog-tutorial and successfully got it to work:
http://jugojava.blogspot.com/2011/02/jdbc-security-realm-with-glassfish-and.html
I have named my two entities Group and User. The have a bi-directional many-to-many relationship.
Now the reason I have done it as in the blog is because I am making an administrator page where I want to be able to add new users. I also let users have the oppertunity to register them self, and they will have the role user.
#Entity
public class Group implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String groupName;
#ManyToMany
#JoinTable(joinColumns = {#JoinColumn(name="group_id")}, inverseJoinColumns = {#JoinColumn(name="user_id")})
private List<User> users;
....
}
and
#Entity
#Table(name = "app_user")
public class User implements Serializable {
public static final String ALL = "User.all";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
private Integer age;
private String username;
private String email;
private String password;
#ManyToMany(mappedBy = "users")
private List<Group> groups;
....
}
My question is how I would assign the group user to a user when it register without me picking the groups from a list in the view?
This is what I have done in the application code but it binds the code the the id of the group in the database, are there better ways?
Method from EJB
public void persistAsUser(User user) {
Group group = new Group(2L, "user");
user.addGroup(group);
userRepository.persist(user);
}
You may want to define a UNIQUE index on the field groupName. Then, create a Data Access Object for the Group table, which provides a method for getting a Group from a groupName (code not tested):
public class GroupDAO implements Serializable {
#PersistenceContext private EntityManager em;
public Group findByGroupName(String groupName) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Group> cq = cb.createQuery(Group.class);
Root<Group> group = cq.from(Group.class);
cq.where(cb.equal(group.get(Group_.groupName), groupName));
TypedQuery<Group> q = em.createQuery(cq);
return q.getSingleResult();
}
}
If you don't like Criteria Builder, you can use a Named Query. Add this annotation to your Group Entity Class:
#NamedQuery(name = "Group.findByGroupname", query = "SELECT f FROM group f WHERE f.groupname = :groupname")
and build a Named Query as follows:
return em.createNamedQuery("Group.findByGroupname").setParameter("groupname", groupName).getResultList();

Categories

Resources