2014-06-13 104 views
0

我想使用Spring建立一个网站。 我已经设法从我设置的数据库中读取数据,但现在在尝试更新其中的行时遇到问题。我正在使用EntityManagermerge()函数。 我没有收到任何错误或异常,它只是不会更新数据库上的数据。Spring框架无法保存在数据库中使用EntityManager.merge()

我会尽力给出所有相关的代码。

我想改变的实体类: 我已经设法从数据库中填充它,所以我认为它应该没问题。

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 
} 

} 

的DAO:IM使用update(Benutzer benutzer)的方法时,尝试更新在DB的apropriate collumn。

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; 
} 

} 

这卡列斯在saveBenutzerdaten()update(Benutzer benutzer)功能权限的代码底部的控制器类:

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"; 
} 

} 

我已经一直在寻找一个相当长时间的解决方案,而且我也发现了很多人有类似的问题,但不是他们的解决方案为我工作。我真的希望有人发现这个问题。开始变得非常沮丧。只需询问是否需要查看更多代码或相关数据。

此外,如果你发现任何我应该改变,请告诉我。我是Spring的新手,不确定我是否做得很好。特别是用我处理登录用户的方式(可能不是将他保存在DAO对象中的一个很好的解决方案?)。


我找到了解决方案。在添加服务类并添加到我的mvc-dispatcher-servlet.xml后,它工作正常。 (sopro.mvc.swm.service是我有我的服务类的包)。

回答

0

我找到了解决方案。在我添加一个服务类后,它运行良好,并将 添加到我的mvc-dispatcher-servlet中。xml,以及applicationContext.xml。 (sopro.mvc.swm.service是我有我的服务类的包)。

谢谢你们:)

0

尝试以下操作:

在控制器尽量不要用户private Benutzer currentlyActive即时变量。 至少在saveBenutzer方法中,不要使用currentlyActive对象,而应从模型属性@ModelAttribute("newBenutzerdaten") Benutzer benutzerdaten中检索对象标识。将id存储在网页中的某个隐藏变量中,以便它将在modelAttribute中可用,并将此modelAttribute直接传递给update方法。

+0

是否有可能从一个控制器达到数据,处理例如login.jsp的另一个CONTROLER处理针对home.jsp?我应该在哪里添加modelattribute?这个问题是我首先在DAO中添加当前活动属性的原因。 – Frager007

+0

你可以使用flash属性[Spring MVC Flash Attributes](http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-flash-attributes)。 ...这是一个关于在重定向期间使用这个Flash属性的好教程.. [FlashAttribute教程](http://viralpatel.net/blogs/spring-mvc-flash-attribute-example/) –

+0

我已经摆脱了即时变量当前在控制器中处于活动状态,如在DAO类中。尽管如此,仍然没有工作。我将用户存储在控制器的@SessionAttribute中。这可能会以某种方式阻止entetymanager更新数据库中的Benutzer变量?如果我只将ID存储在会话属性中,会有帮助吗? – Frager007

0

您发布了很多代码,我相信您可以轻松地将其缩减为展示该问题的最小示例。但是,您没有发布配置。

经常遇到的一个问题是@Transactional在Spring MVC上下文中可能不起作用,当然,@Controller不能在其中工作。请参阅我在https://stackoverflow.com/a/19388280/2621917中的回答,这可能或可能不相关。

+0

感谢您花时间编辑我的拼写:)我确信我可以发布更少的代码,但就像我说的,我是新来的春天,我不知道什么是相关的。我只是遵循一个基本的教程,然后开始我的项目,这个项目比tuto分配的更大,更复杂。但是,刚才我添加了一个Service类,在使用该类之后,我得到了这个异常:org.springframework.transaction.TransactionSystemException:无法提交JPA事务;嵌套异常是javax.persistence.RollbackException:提交事务时出错 – Frager007

相关问题