0

I’m trying to set up a website using Spring. I already managed to read data from a database I've set up, but now encountered a problem when trying to update rows in it. I'm using the merge() function of the EntityManager. I don't get any errors or exceptions, it just wont update the data on the DB.

I'll try to give all relevant code.

The entity class I want to change: I already managed to fill it with data from the DB, so I think it should be alright.

Benutzer.java

@Entity
@Table(name = "BENUTZER")
    @NamedQueries({
    @NamedQuery(name = "Benutzer.findAll", query = "SELECT tt FROM Benutzer tt"),
    @NamedQuery(name = "Benutzer.findByKennung", query = "SELECT tt FROM Benutzer tt WHERE tt.kennung = :kennung"),
public class Benutzer {

@Id
@GeneratedValue
private BigInteger oid;

@Size(min = 2, max = 20)
@Pattern(regexp = "[A-Za-z ]*", message = "Titel darf nur Buchstaben und Leerzeichen beinhalten")
private String titel;

@NotNull
@Size(min = 2, max = 25)
@Pattern(regexp = "[A-Za-z ]*", message = "Anrede darf nur Buchstaben und Leerzeichen beinhalten")
private String anrede;

@NotNull
@Size(min = 2, max = 45)
@Pattern(regexp = "[A-Za-z ]*", message = "Name darf nur Buchstaben und Leerzeichen beinhalten")
private String name;

@NotNull
@Size(min = 2, max = 45)
@Pattern(regexp = "[A-Za-z ]*", message = "Vorname darf nur Buchstaben und Leerzeichen beinhalten")
private String vorname;

@NotNull
@Size(min = 6, max = 16)
@Pattern(regexp = "[0-9]*", message = "Telefonnummer darf nur aus Zahlen bestehen")
private String telefonnummer;

@Size(max = 25, message = "Fax darf maximal 25 Zahlen beinhalten")
@Pattern(regexp = "[0-9]*", message = "Fax darf nur aus Zahlen bestehen")
private String fax;

@NotNull
@Size(min = 2, max = 45)
@Pattern(regexp = "[A-Za-z0-9 ]*", message = "Straße darf nur Buchstaben, Leerzeichen und Hausnummer beinhalten")
private String strasse;

@NotNull
@Size(min = 2, max = 45)
@Pattern(regexp = "[A-Za-z0-9 ]*", message = "Ort darf nur Buchstaben, Leerzeichen und PLZ beinhalten")
private String ort;

@NotNull
@Size(min = 2, max = 45, message = "E-mail muss zwischen 2 und 45 Zeichen beinhalten")
private String email;

private boolean freigeschaltet;

@Temporal(TemporalType.TIMESTAMP)
private Date sperrbeginn;

@NotNull(message = "Kennung darf nicht leer sein")
private String kennung;

@NotNull
private String passwort;

@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "BENUTZER_has_KUNDE", joinColumns = { @JoinColumn(name = "BENUTZER_oid") }, inverseJoinColumns = { @JoinColumn(name = "KUNDE_oid") })
private List<Kunde> kundenListe;

public Benutzer() {

};

+getter and setter
}

}

The DAO : Im using the update(Benutzer benutzer) method in it to try updating the apropriate collumn in the DB.

BenutzerDaoImpl.java

@Transactional
@Repository("benutzerDao")
public class BenutzerDaoImpl implements BenutzerDao{

private EntityManager em;

public EntityManager getEm() {
    return em;
}

@PersistenceContext (type = PersistenceContextType.TRANSACTION)
public void setEm(EntityManager em) {
    this.em = em;
}

public Benutzer findById(BigInteger id) {
    return em.find(Benutzer.class, id);
}

public Benutzer findByKennung(String kennung) {
    Query benutzerByKennung = em.createNamedQuery("Benutzer.findByKennung");
    benutzerByKennung.setParameter("kennung", kennung);
    return (Benutzer) benutzerByKennung.getSingleResult();
}

public List<Benutzer> findAll() {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Benutzer> criteria = cb.createQuery(Benutzer.class);
    Root<Benutzer> benutzer = criteria.from(Benutzer.class);

    criteria.select(benutzer).orderBy(cb.asc(benutzer.get("name")));
    return em.createQuery(criteria).getResultList();
}

public void register(Benutzer benutzer) {
    em.persist(benutzer);
    return;
}

public void delete(BigInteger id) {
    Benutzer benutzerTemp = findById(id);
    em.remove(benutzerTemp);
}


public void update(Benutzer benutzer) {
    Benutzer benutzerTemp = findById(benutzer.getOid());
    benutzerTemp.setTelefon_vorwahl(benutzer.getTelefon_vorwahl());
    benutzerTemp.setTelefon_nummer(benutzer.getTelefon_nummer());
    benutzerTemp.setFax_vorwahl(benutzer.getFax_vorwahl());
    benutzerTemp.setFax_nummer(benutzer.getFax_nummer());
    benutzerTemp.setStrasse(benutzer.getStrasse());
    benutzerTemp.setStrasse_nummer(benutzer.getStrasse_nummer());
    benutzerTemp.setOrt(benutzer.getOrt());
    benutzerTemp.setEmail(benutzer.getEmail());
    benutzerTemp.setKennung(benutzer.getKennung());
    em.merge(benutzerTemp);
    return;
}

}

And the Controller class that calles the update(Benutzer benutzer) function in saveBenutzerdaten() right at the bottom of the code:

BenutzerdatenController.java

@Controller
@SessionAttributes("activeUser")
public class LoginController {

private BenutzerDao benutzerDao;

private KundeDao kundeDao;

private AnlageDao anlageDao;

@Autowired 
public LoginController(BenutzerDao benutzerDao, KundeDao kundeDao, AnlageDao anlageDao){
    this.benutzerDao = benutzerDao;
    this.kundeDao = kundeDao;
    this.anlageDao = anlageDao;
}

@ModelAttribute("activeUser")
   public Benutzer populateActiveUser() {
       return new Benutzer(); // Füllt activeUser beim ersten mall wenn es null ist.
   }

@RequestMapping(value = "/login" ,method = RequestMethod.GET)
public String login(Model model, SessionStatus status) {
    status.setComplete();
    model.addAttribute("benutzerLoginDaten", new Login());
    return "login";
}


@RequestMapping(value = "/login" ,method = RequestMethod.POST)
public String requestLogin(
        @Valid @ModelAttribute("benutzerLoginDaten") Login logindaten,
        BindingResult result, Model model, final RedirectAttributes redirectAttributes) {

    if (!result.hasErrors()) {
        if (logindaten == null) {
            String error = "Fehler beim login";
            model.addAttribute("error", error);
            return "login";
        }
        Benutzer user = null;
        try{
            user = benutzerDao.findByKennung(logindaten.getKennung());
        }catch(Exception e){
            String error = "Unbekannter Benutzer";
            model.addAttribute("error", error);
            return "login";
        }
        if (user == null) {
            String error = "Unbekannter Benutzer";
            model.addAttribute("error", error);
            return "login";
        }
        String pw = user.getPasswort();
        if (pw.equals(logindaten.getPasswort())) {
            redirectAttributes.addFlashAttribute("activeUser", user);
            return "redirect:/home.html";
        } else {
            String error = "Passwort falsch";
            model.addAttribute("error", error);
            return "login";
        }
    }
    return "login";
}

@RequestMapping(value = "/home",method = RequestMethod.GET)
public String home(@ModelAttribute("activeUser") Benutzer activeUser ,Model model, final RedirectAttributes redirectAttributes){
    if(activeUser == null){
        return "redirect:/login.html";
    }
    if(activeUser.getKennung()==null){
        //falls activeUser == null, hat sich kein Benutzer eingelogt
        //und wird damit auf die loginseite weitergeleitet.
        return "redirect:/login.html";
    }

    //erstellen der Anlagenliste mit dazugehörigem Kunden:
    //i und j werden zum mitzählen der schleifendurchläufe verwenden
    //sum zählt die benotigte größe für die Anlagenliste. (summe der anlagen aller kunden zu denen der benutzer zugriff hat)
    int i=0, j = 0, sum = 0;
    List<Kunde> kunden = activeUser.getKundenListe();
    for(i = 0 ; i< kunden.size(); i++){
        List<Anlage> anlagen = kundeDao.getAllAnlagen(kunden.get(i));
        sum += anlagen.size();
    }

    //auffüllen der attribute für select anlagenListe (beschreibung: anlagenbeschreibung, ids: anlagenids):
    String[] beschreibung = new String[sum];
    BigInteger[] ids = new BigInteger[sum];

    Select anlagenListe = new Select();
    sum = 0;
    for(i = 0 ; i < kunden.size(); i++){
        List<Anlage> anlagen = kundeDao.getAllAnlagen(kunden.get(i));
        for(j = 0; j <anlagen.size(); j++){
            //beschreibung format : Anlagenbezeichnung (kunde)
            beschreibung[sum] = 
                    ""+anlagen.get(j).getBezeichnung() + 
                    " (" + 
                            ((kunden.get(i).isFirma())?
                                    kunden.get(i).getFirmenname()
                                    :
                                        kunden.get(i).getPrivatperson_nachname() +
                                    " " +
                                    kunden.get(i).getPrivatperson_vorname()) +
                     ")";
             ids[sum++]= anlagen.get(j).getOid();
         }


     }
    anlagenListe.setSelectOptions(beschreibung);
    anlagenListe.setIds(ids);
    model.addAttribute("activeUser", activeUser);
    model.addAttribute("selection", anlagenListe);
    return "home";
}


@RequestMapping(value = "/home", method = RequestMethod.POST)
public String selectAnlage(@Valid @ModelAttribute("selection") Select selection, BindingResult result, Model model) {

    if(!result.hasErrors()) {
        Anlage anlage = anlageDao.findById(selection.getSelectionOid());
        System.out.println("anlage--  id: " + anlage.getOid() + "  Bezeichnung: " + anlage.getBezeichnung());
        return "home";
    }
    return "home";

}



@RequestMapping(value = "/benutzerdaten", method = RequestMethod.GET)
public String benutzerdaten(@ModelAttribute("activeUser") Benutzer benutzer,Model model){
    return "benutzerdaten";
}


@RequestMapping(value = "/benutzerdaten", method = RequestMethod.POST)
public String saveBenutzerdaten(
        @ModelAttribute("activeUser") Benutzer benutzer,
        Model model) {
    benutzerDao.update(benutzer);
    return "benutzerdaten";
}

}

I've been looking for a solution for quite a long time now, and I've also found quite a lot of people having simular problems, but none of their solutions worked for me. I really hope someone finds the problem. Starting to get quite frustrated. Just ask If you need to see some more code or relevant data.

Also, If you notice anything I should change, please tell me. I'm new to Spring and not sure I'm doing everything right. Especially with the way I handle the logged in User (probably not a good solution to save him in the DAO object?).


I've found a solution. It worked fine after I added a service class and added to my mvc-dispatcher-servlet.xml. (sopro.mvc.swm.service is the package where I have my service classes).

Frager007
  • 46
  • 7

3 Answers3

0

Try following :

In controller try not to user private Benutzer currentlyActive as instant variable. At-least in saveBenutzer method do not use currentlyActive object, instead retrive the object id from the model attribute @ModelAttribute("newBenutzerdaten") Benutzer benutzerdaten. Store id in some hidden variable in the web page so it will be available in the modelAttribute, and pass this modelAttribute directly to the update method.

Pranav Maniar
  • 1,545
  • 10
  • 22
  • Is it possible to reach data from one controller, handling for example the login.jsp to another controler handling home.jsp? Where should I add the modelattribute? That question is the reason I added the currently active attribute in the DAO in the first place. – Frager007 Jun 14 '14 at 10:54
  • You can use flash attributes [Spring MVC Flash Attributes](http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-flash-attributes).... Here's a good tutorial on using this flash attributes during redirect.. [Tutorial on FlashAttribute](http://viralpatel.net/blogs/spring-mvc-flash-attribute-example/) – Pranav Maniar Jun 14 '14 at 14:50
  • I've got rid of the instant variable currently active in the controller, as in the DAO class. Still dosen't work though. I stored the user in an @SessionAttribute in the controller. could this somehow prevent the entetymanager to update the Benutzer variable on the Database? Would it help if I only store the id in an session attribute? – Frager007 Jun 15 '14 at 11:41
  • `@SessionAttribute` should not be causing the problem. It should be something else... Meanwhile can you please quickly try one thing.. Remove the `@Transactional` annotation from dao and place it on the methods which of the controller which is creating/updating/deleting the object and see if it helps.. I will try to simulate problem on my end and try to find the answer – Pranav Maniar Jun 15 '14 at 11:53
  • I've updatet the controller and Dao in my Question post. Would be nice if you could take a look at the controller and the update funktion from the Dao. I't took me quite some time to edit it to the way it is now. to bad it still dosen't work :/ Could It be that the @Transactional annotation dosen't work? Maybe I have set up the spring configurations the wrong way? – Frager007 Jun 15 '14 at 18:58
0

You posted a lot of code, and I’m sure you could easily have cut it down to present a minimal example showing the problem. However, you did not post the configuration.

One problem frequently encountered is that @Transactional might not work in a Spring MVC context, while, of course, @Controller does not work outside of one. Please refer to my answer in https://stackoverflow.com/a/19388280/2621917, which might or might not be relevant.

Community
  • 1
  • 1
Michael Piefel
  • 18,660
  • 9
  • 81
  • 112
  • Thanks for taking the time to edit my spelling :) I'm sure I could have posted less code, but like I said, I'm new to spring and I'm not shure what is relevant. I just followed a basic tutorial, and after that started my project, wich is allot bigger and complicaited than the tuto was. However, just now I added a Service class, and after using that, I get this Exception: org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction – Frager007 Jun 15 '14 at 19:43
0

I've found a solution. It worked fine after I added a service class and added to my mvc-dispatcher-servlet.xml, aswell as to applicationContext.xml. (sopro.mvc.swm.service is the package where I have my service classes).

Thanks Guys :)

Frager007
  • 46
  • 7