0

I'm working on a Spring-MVC project, trying to update a user's username and password using jpa. But I don't seem to be making any progress. :D

I checked other questions like this one and tried to use their approved answers for my case. Alas, nothing changes in my db.

By far, I have tried these methods and none has worked:

  1. using persist before set, as suggested here

  2. using merge after set as suggested here

  3. commiting a transaction manually as suggested here.

Unfortunately, this class has a lot of foreign keys from all around my DB, and I can't safely remove the old one and add a new Dept with new data in it. So, here goes my update method -in DAO level of course- would someone please suggest a new way to update username and password here?

@Transactional
    public  Dept updateDept(int depId, String u, String p) {
        System.err.println("successfully reached DAO");
        Dept dep=entityManager.find(Dept.class,depId);

        dep.setUname(u);
        dep.setPassword(p);
        entityManager.merge(dep);

        return entityManager.find(Dept.class,depId); //just to check if update really happened, which did not
    }//end of update Dept

edit: Ok, so it is getting really complicated. I'm really a newbie in this area, so I try to give you as much detail as possible.

These are the only parts I was allowed to change, and I have to consider that any other configuration to other parts like JPA etc. is done by my senior team mate and is done correctly.

This is my controller which is supposed to update username and password of department manager, and send user back to their first page:

@RequestMapping(value="/infoEdit", method=RequestMethod.POST)
    public String editManager(HttpServletRequest req, @RequestParam("username") String  usernname , @RequestParam("password") String password , Model model) {
        int id= (Integer) req.getSession().getAttribute("id");

        boolean isUpdated=managerManagerImpl.updateUserPass(id,usernname,password);
        System.err.println(isUpdated);
        Dept d= managerManagerImpl.getDeptByManagerId(usernname,password);
        if (d!=null)

        return "themanager/managerFirstPage";

    }

In managerManagerImpl - implementation of managerManager interface , updateUserPass() goes like this:

@Override
    public Boolean updateUserPass(int id, String usernname, String password) {
        Dept dept=managerDAOImpl.getDept(id); // who is this?
        Dept possibleDup=managerDAOImpl.getDept(usernname);//maybe this username is taken
        Dept newDep=null;
        if(possibleDup==null || (possibleDup!=null && possibleDup.getId()==dept.getId())){//username is not taken
            System.err.println("going to update it!!");
            newDep=managerDAOImpl.updateDept(dept.getId(),usernname,password);
            System.err.println("newDep data here            : " + newDep.getId() + "// "+newDep.getUname());
            Dept newnewDept = managerDAOImpl.getDept(id);
            if(newnewDept!=null)
                System.err.println("&& newnewDep data here            : " + newnewDept.getId() + "// "+newnewDept.getUname());
        }
        Boolean isUpdated=(null!=newDep && newDep.getId()==dept.getId());
        return isUpdated;
    }

and this is my whole managerDAOImpl class:

@Repository
public class TheManagerDAOImpl {

    public TheManagerDAOImpl() {
    }

    @PersistenceContext
    public EntityManager entityManager;


    @Transactional
    public Prof getManager(String usern){
        String hql="SELECT p FROM Dept  p WHERE p.uname=:username";
        Query q= entityManager.createQuery(hql);
        q.setParameter("username",usern);
        List<Prof> res = (List<Prof>) q.getResultList();
        return res == null || res.size() == 0 ? null : res.get(0);
    }
    @Transactional
    public Dept getDept(int managerId) {
        String hql= "SELECT d FROM Dept  d WHERE  d.id=:idHere";
        Query q= entityManager.createQuery(hql);
        q.setParameter("idHere",managerId);
        List<Dept> res = (List<Dept>) q.getResultList();
        return res == null || res.size() == 0 ? null : res.get(0);
    }
    @Transactional
    public Dept getDept(String managerId, String managerPass) {
        String hql= "SELECT d FROM Dept  d WHERE d.uname=:username AND d.password=:pass";
        Query q= entityManager.createQuery(hql);
        q.setParameter("username",managerId);
        q.setParameter("pass",managerPass);
        List<Dept> res = (List<Dept>) q.getResultList();
        return res == null || res.size() == 0 ? null : res.get(0);
    }

    @Transactional
    public Dept getDept(String managerId) {
        String hql= "SELECT d FROM Dept  d WHERE d.uname=:username";
        Query q= entityManager.createQuery(hql);
        q.setParameter("username",managerId);
        List<Dept> res = (List<Dept>) q.getResultList();
        return res == null || res.size() == 0 ? null : res.get(0);
    }
    @Transactional
    public  Dept updateDept(int depId, String u, String p) {
        System.err.println("**************************here in dao");
        Dept dep=entityManager.find(Dept.class,depId);

        dep.setUname(u);
        dep.setPassword(p);
        entityManager.merge(dep);

        return entityManager.find(Dept.class,depId);
    }//end of update Dept


}

Just to mention, those System.error stuff are used to make sure it actually calls these methods, and are completely irrelevant.

Sarah_A
  • 130
  • 2
  • 17
  • could you share you persistence configuration? – Dmitry Senkovich Jun 23 '17 at 13:39
  • entityManager.merge() is completely useless: you have a managed entity already. And the return is strictly equivalent to `return dep`. My guess is that the problem is how you get the entity manager, or the instance of the class containing this method. Or in your spring configuration. You need to show us more of your code and config. – JB Nizet Jun 23 '17 at 13:45
  • probably your JPA configuration in spring is incorrectly configured. – K.Nicholas Jun 23 '17 at 13:48
  • @DmitrySenkovich I'm not really a pro in these stuff, could you please explain exactly which file should I add to my question? As far as I know, there is a persistence context thing here which I just mentioned to initiate my entityManager. sorry :"> – Sarah_A Jun 23 '17 at 13:50
  • @Sarah Amini I need you persistence set up. I may be found in a Spring xml configuration file if you use Spring or in java configuration. How do you set up `entityManagerFactory`? – Dmitry Senkovich Jun 23 '17 at 13:52
  • @KarlNicholas I don't have access to all parts of this project, just controller,manager(service part) and DAO. So I'm 90% sure I haven't changes JPA config. Did I -or any of my team mates- have to do that? – Sarah_A Jun 23 '17 at 13:52
  • @SaraAmini Well, you should just return dep from the merge and it should contain the updated username and password. If you don't have access to the rest of the configuration and it's not being updated in the database it's not your problem and you should be talking to that other person instead of SO. – K.Nicholas Jun 23 '17 at 13:54
  • `entityManager.find(Dept.class,depId)` will not go to DB, it will get entity from EntityManager cache itself. You need to query (check for update) in a separate transaction. You are returning before commit itself. – fg78nc Jun 23 '17 at 13:58
  • @DmitrySenkovich I added persistence.xml codes to my question. Did I get you right? – Sarah_A Jun 23 '17 at 13:58
  • @Sarah Amini Not exactly. I would to see all the persistence stuff. In particular, I need to see if you set up a transaction manager – Dmitry Senkovich Jun 23 '17 at 14:00
  • How do you obtain your EntityManager, EntityManagerFactory and TransactionManager? Please list your code. – fg78nc Jun 23 '17 at 14:05
  • @fg78nc I just have entitymanager here. – Sarah_A Jun 23 '17 at 14:20
  • You can't get EntityManager out of thin air. Either it has to be injected with `@PersistenceContext` (container-managed persistence context) or you can obtain it from EntityManagerFactory(bean-managed persistence context) as well as you can get it bootstrap from Persistence class. Which way did you go? – fg78nc Jun 23 '17 at 14:29
  • @fg78nc if I undestood you correctly, I've used the first way. It can be seen in my code, right? – Sarah_A Jun 23 '17 at 14:51
  • Please see my answer below, it is too long, and does not fit in comments. – fg78nc Jun 23 '17 at 15:10

2 Answers2

0

You are getting container-manager persistence context, which has to get JTA datasource, but as I saw before(you have already removed it) from your persistence.xml, you are using resource local transactions (by specifying jdbc resource).

Correct configuration should be (for XML config)

1) Your datasource

<jdbc:embedded-database id="dataSource" type="H2">
    </jdbc:embedded-database>
// or jdbc:initialize-database for non-embedded

2) Your transaction manager

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
                <property name="entityManagerFactory" ref="emf"/>
            </bean>

2.1) As you are using annotation to do transaction demarcation you need

<tx:annotation-driven transaction-manager="transactionManager" />

3) Your entity manager factory

bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
            </property>
            <property name="packagesToScan" value="com.myPackage"/>
            <property name="jpaProperties">
                <props>
                    <prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
                    <prop key="hibernate.max_fetch_depth">3</prop>
                    <prop key="hibernate.jdbc.fetch_size">50</prop>
                    <prop key="hibernate.jdbc.batch_size">10</prop>
                    <prop key="hibernate.show_sql">true</prop>
                </props>
            </property>
        </bean>
fg78nc
  • 3,867
  • 1
  • 11
  • 26
  • Sorry, I thought that file was irrelevant. I was offered a short solution, tried it out and it worked. not sure if it was a good one. But since it solved my issue, I didn't finish all of these changes you suggested. But I really appreciate your help and do all these changes to prevent further problems. Thank you so much! – Sarah_A Jun 23 '17 at 17:59
0

I found another way to do updates, which I'm not sure if it has any drawbacks, or it would blow my code up in the future. But since it solved this issue for now, I share it here. Maybe it will help.

For now I clear my entityManager before updating any existing entity. Somehow like this:

@Transactional
    public  void updateDept(Dept dep,String username, String password)  {
        entityManager.clear();
        dep.setUname(username);
        dep.setPassword(password);
        entityManager.merge(dep);
    }//end of update Dept

Surprisingly, it now works fine and commits updates on DB.

Sarah_A
  • 130
  • 2
  • 17