How should I manage the create, edit and delete operations with entites as simple as possible?
For example:
User:
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
...
// Item can't exist without user
#OneToMany(cascade=CascadeType.ALL,mappedBy = "user",orphanRemoval=true)
private Set<Item> items = new HashSet<Item>();
public Set<Item> getItems() { return items; }
public void addItem(Item item) {
items.add(item);
}
public void removeItem(Item item) {
if(!items.contains(item)) return;
items.remove(item);
}
// Group can exist without a user
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH},mappedBy="users")
private Set<Group> groups = new HashSet<Group>();
public Set<Group> getGroups() { return groups; }
public void setGroups(Set<Group> groups) { this.groups = groups; }
public void addGroup(Group group) {
groups.add(group);
}
publi void removeGroup(Group group) {
if(!groups.contains(group)) return;
groups.remove(group);
}
...
}
Group:
#Entity
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
...
#ManyToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinTable(name = "GroupToUser", joinColumns =
#JoinColumn(name = "GroupId", referencedColumnName="Id"), inverseJoinColumns =
#JoinColumn(name = "UserId", referencedColumnName="Id"))
private Set<User> users = new HashSet<User>();
public Set<User> getUsers() { return users; }
public void setUsers(Set<User> users) { this.users = users; }
public void addUser(User user) {
user.addGroup(this);
}
publi void removeUser(User user) {
if(!users.contains(user)) return;
users.remove(user);
}
...
}
Item:
#Entity
public class Item {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
...
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REFRESH})
#JoinColumn(name="UserId")
private User user;
public Set<User> getUser() { return user; }
public void setUser(User user) {
this.user = user;
}
publi void removeUser() {
this.user = null;
}
...
}
Am I using the jpa annotations right?
What should I write here?
EntityManager em = getEntityManager();
em.getTransaction().begin();
???
em.getTransaction().commit();
Do I have to just call the em.remove/persist/merge methods for delete/create/edit operations?
And when should I use the javax.persistence.EntityManager.getReference method in these operations?
Find() delivers the entity from the cache of the persistence context or if he is not there, it will be loaded from the database.
GetReference() does not load the entity immediately. A proxy( a certain object, a so called "deputy" with enriched methods for loading the actual entity) is returned. So it is a realisation with help of LazyLoading.
Only if the attributes of the proxy or other persistence methods are needed/called the proxy interacts and loads the actual entity from the database.
Eg:
User us = em.find(User.class, 70992);
GetReference() is used similarly.
User us = em.getReference(User.class, 70922);
If the entity for the user id is not known in the persistence context, an EntityNotFoundException() is thrown.
I usually use getReference method when i do not need to access database state (I mean getter method). Just to change state (I mean setter method).
In above case if I want to update age of user like below after getting user:
setAge(age);
If i call find method, JPA provider, behind the scenes, will call
SELECT NAME, AGE FROM USER WHERE USER_ID = ?
UPDATE USER SET AGE = ? WHERE USER_ID = ?
If i call getReference method, JPA provider, behind the scenes, will call
UPDATE PERSON SET AGE = ? WHERE USER_ID = ?
Because when you call getReference, you will get a proxy object.
For rest we have to use remove, persist and merge like you have said
Personally I recommend reading about the Repository Software Pattern and the Single Responsability Principle.
My idea would be to create, for instance, a UserRepository and another class, like a Controller, would go to that repository after creating the necessary objects and try to persist them.
Should work like this:
First get the entity manager and the transaction as you did, then try to persist() the entities. If the persist() method detects that the entity is in the persistence, it will throw a PersistenceException. Catch it, obtain a new transaction and call the merge() method.
The easiest way is not the best way. The best easiest way is this one, I think (but concerning update actions, you better read more about JPQL namedQueries / orm.xml):
#WebFilter("*.htm")
public class JPAFilter implements Filter {
private static final EntityManagerFactory entityManagerFactory
= Persistence.createEntityManagerFactory(/* yourprojectname */);
private static final ThreadLocal<EntityManager> entityManagers
= new ThreadLocal<>();
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
entityManagers.set(entityManagerFactory.createEntityManager());
EntityManager entityManager = entityManagers.get();
try {
request.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
} finally {
if (entityManager.getTransaction().isActive()) {
entityManager.getTransaction().rollback();
}
entityManager.close();
entityManagers.remove();
}
}
public static EntityManager getEntityManager() {
return entityManagers.get();
}
#Override
public void destroy() {
entityManagerFactory.close();
}
}
----
abstract class AbstractDAO {
protected EntityManager getEntityManager() {
return JPAFilter.getEntityManager()
}
}
----
public class UserDAO extends AbstractDAO {
public void create(User user) {
getEntityManager().persist(user);
}
public User read(long id) {
return getEntityManager().find(User.class, id);
}
public void delete(long id) {
if (user != null) {
getEntityManager().remove(user);
}
}
}
----
abstract class AbstractService {
private EntityManager getEntityManager() {
return JPAFilter.getEntityManager();
}
protected void beginTransaction() {
getEntityManager().getTransaction().begin();
}
protected void commit() {
getEntityManager().getTransaction().commit();
}
protected void rollback() {
getEntityManager().getTransaction().rollback();
}
}
----
public class UserService extends AbstractService {
private final UserDAO userDAO = new UserDAO();
public void create(User user) {
beginTransaction();
userDAO.create(user);
commit();
}
public User read(long id) {
return userDAO.read(id)
}
public void delete(long id) {
userDAO.delete(id);
}
}
----
#WebServlet("/users.htm")
public class ManageUsersServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final String VIEW = "/WEB-INF/JSP/users.jsp";
private final transient UserService userService = new UserService();
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// here you do whatever you want using your userService methods.
}
}
P.S. Do not forget to lock records from database when updating (using pessimistic lock or the catching an optimistic lock exception).
You can also find lots about it if you search for "CRUD Operations with JPA". First tutorial I found is this one: http://www.objectdb.com/java/jpa/persistence/crud
Am I using the jpa annotations right?
At first glance, I'd only question the absence of a #Version field, which is necessary for the EntityManager to perform optimistic locking, which is the standard safeguard against lost updates unless you use a serializable isolation level (which would require special configuration on many database systems).
Do I have to just call the em.remove/persist/merge methods for delete/create/edit operations?
That is the easiest and usually best way.
And when should I use the javax.persistence.EntityManager.getReference method in these operations?
getReference is useful if you want to refer to an entity without loading its data from the database. For instance, you could have:
public void updateUser(Item item, int userId) {
item.setUser(entityManager.getReference(User.class, userId)); // does not require a query
entityManager.merge(item);
}
Transactions
You'll want to rollback the transaction if an exception is thrown and close the entityManager once you are done with it (both in case of success and failure).
On a related note, if your application is not tiny, you'll want to look into declarative transaction management so you don't have to code them for every operation. For instance, in Spring you'd simply annotate the class with #Transactional to have Spring start (and end) a transaction whenever a method is invoked.
Related
I'm using jquery Datatables together with Spring JPA.
I want to create a custom Query so that my Datatable will show a list of items based on the id of a ManyToOne related object.
PS. I have obviously declared Repositories, Mapper and Entities for these DTOs, I'm just avoiding to write all the classes because I find it useless.
public class SezioniDTO {
private static final long serialVersionUID = 1L;
private long id;
private LocalDate sezDtaggiornamento;
private Comune Comune;
}
public class Comune {
private static final long serialVersionUID = 1L;
private long id;
private String comCap;
private String comCodbelfiore;
private String comCodcomune;
}
These are my classes (i use mapstruct to map the dtos from the entities).
How can i use criteria builder inside my repository and services to search for Sezionis based on Comunes id?
I'm new to QueryDSL and Specifications, i just would like to obtain something like this:
#Query("Select * from Sezioni s WHERE s.id_Comune = :id", native="true")
public DataTablesOutput <Object> findByField (#Param(value="id", input);
This is the current Service Implementation
#Service
public class SezioniServiceImpl implements SezioniService{
#Autowired
SezioniRepository repo;
#Autowired
SezioniMapper mapper;
#Autowired
SezioniSpecifications sezSpec;
#Override
public List<SezioniDTO> findAll() {
return repo.findAll().stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
.collect(Collectors.toList());
}
#Override
public List<SezioniDTO> findByIdComune(Long idcom){
return repo.findSezionibyIdComune(idcom).stream().map(x -> mapper.entityToDto(x, new CycleAvoidingMappingContext()))
.collect(Collectors.toList());
}
#Override
public SezioniDTO save(SezioniDTO entity) {
return null;
}
#Override
public Optional<SezioniDTO> findById(Long id) {
// TODO Auto-generated method stub
return null;
}
#Override
public void delete(SezioniDTO entity) {
// TODO Auto-generated method stub
}
#Override
public void deleteById(Long id) {
// TODO Auto-generated method stub
}
#Override
public long count() {
// TODO Auto-generated method stub
return 0;
}
#Override
public DataTablesOutput<SezioniDTO> getSezioniTable(#Valid DataTablesInput input) {
return repo.findAll(input, null, null, a -> mapper.entityToDto(a, new CycleAvoidingMappingContext()) );
}
}
and the current Repository for SezioniDTO
#Repository
public interface SezioniRepository extends JpaRepository<Sezione,Long>, JpaSpecificationExecutor<Sezione>, DataTablesRepository<Sezione,Long> {
#Query(value = "SELECT * FROM db.sezione WHERE sez_com_prg = :id ORDER BY sez_numsezione", nativeQuery = true)
public List <Sezione> findSezionibyIdCom(#Param(value = "id") Long id);
}
Where Sezione is the current Entity. As you can see, it extends , and DataTablesOutput work only with Specifications, which I haven't understood at all.
I simply would like to create a method similar to the public List I have in the repo, but with a DataTablesOutput return instead.
Define Entities:
#Entity
public class Sezioni {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private LocalDate sezDtaggiornamento;
#OneToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "comune_id")
private Comune Comune;
// getters & setter are omitted
}
and
#Entity
public class Comune {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String comCap;
private String comCodbelfiore;
private String comCodcomune;
// getters & setter are omitted
}
Define repository
#Repository
public interface SezioniRepository extends JpaRepository<Sezioni, Long> {
#Query("select s from Sezioni s where s.Comune.id = :id")
List<Sezioni> findByComuneId(Long id);
}
Use (here in test)
#DataJpaTest
class SezioniRepositoryTest {
#Autowired
SezioniRepository sezioniRepository;
#BeforeEach
void setUp() {
Comune comune = new Comune();
comune.setComCap("cap42");
comune.setComCodcomune("cod43");
Sezioni sezioni = new Sezioni();
sezioni.setComune(comune);
sezioni.setSezDtaggiornamento(LocalDate.of(1970, 1, 1));
sezioniRepository.save(sezioni);
}
#Test
void test() {
List<Sezioni> sezionis = sezioniRepository.findByComuneId(1L);
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
}
Next you can use MapStruct to map entities into DTO (if you prefer to expose DTO on your API)
Criteria Builder's advantage is to build queries dynamically upon your business login needs:
Consider next example:
#Service
public class SezioniQuery {
#PersistenceContext
private EntityManager entityManager;
List<Sezioni> select(TriFunction<CriteriaBuilder, Root<Sezioni>, CriteriaQuery<Sezioni>, CriteriaQuery<Sezioni>> builder) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Sezioni> query = criteriaBuilder.createQuery(Sezioni.class);
// SQL FROM clause
Root<Sezioni> from = query.from(Sezioni.class);
// SQL SELECT clause
CriteriaQuery<Sezioni> select = query.select(from);
// build WHERE somewhere later
CriteriaQuery<Sezioni> apply = builder.apply(criteriaBuilder, from, query);
// execute
TypedQuery<Sezioni> typedQuery = entityManager.createQuery(apply);
return typedQuery.getResultList();
}
}
^^ here we define boilerplate.
Next we can reuse it to build different queires:
// #BeforeEach void setUp() {...} omitted see prev. answer
#Test
void testEqual() {
Long id = 1L;
List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
// WHERE id=1
query.where(cb.equal(from.get("id"), id)));
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
#Test
void testGreater() {
List<Sezioni> sezionis = sezioniQuery.select((cb, from, query) ->
// WHERE id > 0
query.where(cb.gt(from.get("id"), 0)));
assertEquals(1, sezionis.size());
assertEquals("cap42",sezionis.get(0).getComune().getComCap());
}
So, using CriteriaBuilder you can build queries dynamically but this requires a bit more code, non-type-safe code.
Whereas JpaRepository extension is type-safe but non-dynamiŃ
I have a SDR project and I am successfully validating the user entity for POST request but as soon as I update an existing entity using either PATCH or PUT the DB is updated BEFORE the validation is executed (the validator is being executed and error is returned but the DB is being updated anyway).
Do I need to setup a separate config for update ? Am I missing an extra step for that?
Entity
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
public class Member {
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "member_id_gen")
#SequenceGenerator(name = "member_id_gen", sequenceName = "member_id_seq")
#Id
#JsonIgnore
private long id;
#Version
private Integer version;
#NotNull
protected String firstName;
#NotNull
protected String lastName;
#Valid
protected String email;
}
Repository
#RepositoryRestResource(collectionResourceRel = "members", path = "member")
public interface MemberRepository extends PagingAndSortingRepository<Member, Long> {
public Member findByFirstName(String firstName);
public Member findByLastName(String lastName);
}
Validator
#Component
public class BeforeSaveMemberValidator implements Validator {
public BeforeSaveMemberValidator() {}
private String EMAIL_REGEX = "^[a-zA-Z0-9._%+-]+#[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$";
#Override
public boolean supports(Class<?> clazz) {
return Member.class.equals(clazz);
}
#Override
public void validate(Object target, Errors errors) {
Member member = (Member) target;
if(ObjectUtils.isEmpty(member.getFirstName())) {
errors.rejectValue("firstName", "member.firstName.empty");
}
if(ObjectUtils.isEmpty(member.getLastName())) {
errors.rejectValue("lastName", "member.lastName.empty");
}
if(!ObjectUtils.isEmpty(member.getDni()) && !member.getDni().matches("^[a-zA-Z0-9]*$")) {
errors.rejectValue("dni", "member.dni.invalid");
}
if(!ObjectUtils.isEmpty(member.getEmail()) && !member.getEmail().matches(EMAIL_REGEX)) {
errors.rejectValue("email", "member.email.notValid");
}
}
}
BeforeSave service
#Service
#RepositoryEventHandler(Member.class)
public class MemberService {
#HandleBeforeCreate
#HandleBeforeSave
#Transactional
public void beforeCreate(Member member) {
...
}
}
I think you should rename your validator, for example, to MemberValidator then assign it as described here:
#Override
protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", new MemberValidator());
v.addValidator("beforeSave", new MemberValidator());
}
But I suggest you to use Bean validation instead of your custom validators. To use it in SDR project you can inject LocalValidatorFactoryBean, then assign it for 'beforeCreate' and 'beforeSave' events in configureValidatingRepositoryEventListener:
#Configuration
#RequiredArgsConstructor // Lombok annotation
public class RepoRestConfig extends RepositoryRestConfigurerAdapter {
#NonNull private final LocalValidatorFactoryBean validatorFactoryBean;
#Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener v) {
v.addValidator("beforeCreate", validatorFactoryBean);
v.addValidator("beforeSave", validatorFactoryBean);
super.configureValidatingRepositoryEventListener(v);
}
}
In this case your SDR will automatically validate payloads of POST, PUT and PATCH requests for all exposed SDR repositories.
See my example for more details.
My professor gave a sample Spring MVC ORM project with Hibernate but I can not figure out the sequence of events involved, in particular about the usage of service business object.
This is just a little part of the project, just to make my ideas clearer.
domain:
#Entity
#Table(name = "department")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long uid;
private String name;
#OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
private List<Employee> employees = new ArrayList<Employee>();
public Department() {
}
public Department(String name) {
this.name = name;
}
// getters, setters, hashcode() and equals(), toString()...
controller:
#Controller
#RequestMapping("/department")
public class DepartmentController {
#Autowired
#Qualifier("departmentBO")
private DepartmentBO departmentBO;
static final Logger logger = Logger.getLogger(DepartmentController.class);
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String departmentHome(Model model) {
logger.debug("department home() invoked");
List<Department> list = departmentBO.findAllDepartments();
model.addAttribute("list", list);
return "departments";
}
// i'll paste just the first controller ;)
business:
public interface DepartmentBO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department department);
public void update(Department department);
}
business/impl:
#Service
#Transactional
public class DepartmentBoImpl implements DepartmentBO {
#Autowired
private DepartmentDAO departmentDao;
static final Logger logger = Logger.getLogger(DepartmentBoImpl.class);
#Override
public void save(Department department) {
departmentDao.save(department);
}
#Override
public void update(Department department) {
departmentDao.update(department);
}
#Override
public void delete(long uid) {
departmentDao.delete(uid);
}
#Override
public List<Department> findAllDepartments() {
return departmentDao.findAllDepartments();
}
#Override
public Department findByUid(Long uid) throws DataAccessException {
return departmentDao.findByUid(uid);
}
}
dao:
public interface DepartmentDAO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department user);
public void update(Department user);
}
dao/impl:
#Repository
public class DepartmentDAOImplSf implements DepartmentDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void delete(long uid) {
Department department = (Department) sessionFactory.getCurrentSession()
.get(Department.class, uid);
sessionFactory.getCurrentSession().delete(department);
}
#Override
public void save(Department department) {
sessionFactory.getCurrentSession().save(department);
}
#Override
public void update(Department department) {
sessionFactory.getCurrentSession().saveOrUpdate(department);
}
#Override
public List<Department> findAllDepartments() {
List<Department> list = (List<Department>) sessionFactory
.getCurrentSession()
.createQuery("FROM Department").list();
return list;
}
#Override
public Department findByUid(Long uid) {
Department department = (Department) sessionFactory
.getCurrentSession().get(Department.class, uid);
return department;
}
}
I know that the order is: domain model -> controller-> service -> dao ->db, but why use a DepartmentBO? and why DepartmentBoImpl autowired DepartmentDao? Who of them act first? Something that i'm not understanding is messing up my conception of how it works and the sequence of the process..
Thanks for your help ;)
EDIT: "
In few words my question is, what is the sequence of this code? user goes on the /home page that redirect on "departments" page. But what happen before this --> "List list = departmentBO.findAllDepartments();" ?;)
When the departmentBO.findAllDepartments() method is called if you look at the code it invokes the sessionFactory. That is an internal factory class in Hibernate that basically builds a transactional connection to the DB in order to run a query. You are defining the query in the createQuery method and then ultimately executing it with the list() method. These two methods are part of the database session that Hibernate has instantiated.
Departments Page -> departmentBO.findAllDepartments() -> sessionFactory -> createQuery -> list()
Or in pseudo code-ish
Departments Page -> execute findAllDepartments method -> fetch / build a database connection -> define the query -> execute the query -> Return the list!
Below is the DAO. I am getting the first UppeningUsers object. Note that here for this function I do not want to return peopleWhoBlockedMe set which is located inside the UppeningUsers..
But in different functions I would like to return that information. Note that Both of them are LAZY fetching. With evict I tried to detach the object but still it did not work.
First of all RESTcontroller is below. Then the DAO code is below. Then two entity descriptions are below.
Question is: I see that until
return new ResponseEntity(returned, HttpStatus.OK);
There is only one query which is the typical select. I do not want hibernate to go and take also UserBlock information of that specific UppeningUser. Because it is not needed for this service response. However even though it is lazy loading for some reason
return new ResponseEntity(returned, HttpStatus.OK);
calls the hibernate. I dont know why in restcontroller still it is connected to the database. I tried evict but didnt work.
The json response is
{"id":7,"peopleWhoBlockedMe":[{"blockedId":7}]}
But I do not want for this function to return this peopleWhoBlockedMe. It can be empty.
PLEASE NOTE that in other service for example I will explictly request this peopleWhoBlockedMe but just for this business logic I do not need this information. So what I can do to prevent this so whenever I actually want to call peopleWhoBlockedMe I can get it. Not automaticly.
#RestController
public class TempController {
#Autowired
UppeningUsersService uppeningUsersService;
#RequestMapping(value = "/testing", method = RequestMethod.GET)
public ResponseEntity<UppeningUsers> getPhotos() {
try {
UppeningUsers returned = uppeningUsersService.getUsersDetailsPartial();
return new ResponseEntity<UppeningUsers>(returned, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
This part is the DAO.
#Repository
public class UppeningUsersDAO {
#Autowired
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sf) {
this.sessionFactory = sf;
}
/**
* Get Existing user. Return error if there is not.
* #param incomingUser user who requested access.
* #return returns the guy information. All information.
*/
#Transactional
public UppeningUsers getUserDetails() throws Exception {
Session session = this.sessionFactory.getCurrentSession();
Query query = session.createQuery("from UppeningUsers ");
UppeningUsers returning = (UppeningUsers) query.list().get(0);
session.evict(returning);
return returning;
}
}
The main table is this one..
#Entity
#Table(name = "uppening_users")
#Proxy(lazy = true)
public class UppeningUsers {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private
int id;
#OneToMany(mappedBy = "blockedId",cascade =CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserBlocks> peopleWhoBlockedMe;
public UppeningUsers() {
super();
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Set<UserBlocks> getPeopleWhoBlockedMe() {
return peopleWhoBlockedMe;
}
public void setPeopleWhoBlockedMe(Set<UserBlocks> peopleWhoBlockedMes) {
this.peopleWhoBlockedMe = peopleWhoBlockedMes;
}
}
Now here is the other table.
#Entity
#Table(name="user_blocks")
#Proxy(lazy = true)
public class UserBlocks {
#Id
#Column(name="id")
#GeneratedValue(strategy= GenerationType.IDENTITY)
int id;
#Column(name = "blocked_id",insertable = false,updatable = false)
private int blockedId;
public int getBlockedId() {
return blockedId;
}
public void setBlockedId(int blockedId) {
this.blockedId = blockedId;
}
}
UPDATE: 2 forgot to add the service
#Service("uppeningUserService")
public class UppeningUsersService {
#Autowired
UppeningUsersDAO uppeningUsersDAO;
public UppeningUsers getUsersDetailsPartial( ) throws Exception {
return uppeningUsersDAO.getUserDetails();
}
}
Jens is right about her sentence. The layer methodology and writing business objects fix the issue. Thank you.
I do everything according to http://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html, but neither in-bean methods nor external ones are ever executed. What might be the cause?
#Entity
#EntityListeners(EntityListener.class)
public class User {
#Id
#Column
#GeneratedValue
private Integer id;
// etc...
#PostConstruct
#PostLoad
#PostPersist
#PostUpdate
public void magic() {
System.out.println("YES I AM EXECUTED!");
System.exit(123);
}
}
OR
#Entity
#EntityListeners(MyListener.class)
public class User {
#Id
#Column
#GeneratedValue
private Integer id;
// etc...
}
+
public class MyListener {
#PostPersist
void postPersist(Object object) {
System.out.println("CAN'T BELEIVE I SEE THIS!");
System.exit(234);
}
}
My code creates, saves and loads beans, but nothing happens on the listeners. This is a piece of the repository thats perform the operations:
#Repository
public class UserRepositoryImpl implements UserRepository {
#Autowired
private SessionFactory sessionFactory;
#Override
public User get(Integer id) {
return sessionFactory.getCurrentSession().get(User.class, id);
}
#Override
public User save(User user) {
Session session = sessionFactory.getCurrentSession();
user = (User) session.merge(user);
session.saveOrUpdate(user);
return user;
}
// etc...
}
Repository methods are called from services like this one:
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Override
public void something() {
// just some repo calls + extra logic
}
}
I do not think I got something special here.
JPA interceptors mechanism work only when you manipulate entities via JPA EntityManager, they have no effect when you're using Hibernate Session directly.
You'll have to implement Hibernate native interceptors if you want to use the Session API.