简体   繁体   English

非空属性引用 null 或瞬态值 - Spring 引导 - Thymeleaf

[英]Not-null property references a null or transient value - Spring Boot - Thymeleaf

I have a problem with the update on my webapp.我的 webapp 更新有问题。

Everytime I try to update an Element i got this error: not-null property references a null or transient value: me.lucacirfeta.model.Element.user每次我尝试更新元素时,我都会收到此错误:非空属性引用 null 或瞬态值:me.lucacirfeta.model.Element.user

To solve this problem i need to add on inside my form an input hidden with all the variable of User model, example:为了解决这个问题,我需要在我的表单中添加一个隐藏的输入,其中包含用户 model 的所有变量,例如:

<input th:field="${element.user.id}" class="form-control" type="text" readonly />
<input th:field="${element.user.username}" class="form-control" type="text" readonly />
<input th:field="${element.user.firstName}" class="form-control" type="text" readonly />
<input th:field="${element.user.lastName}" class="form-control" type="text" readonly />
<input th:field="${element.user.password}" class="form-control" type="text" readonly />

But i don't want to add on my form this hidden data.但我不想在我的表单中添加这些隐藏数据。 I also tried to remove in the Element model "nullable = false" in the JoinColumn annotation but when i try to update Hibernate lost the reference on User setting it up to "null".我还尝试在 JoinColumn 注释中的元素 model“nullable = false”中删除,但是当我尝试更新 Hibernate 时丢失了用户将其设置为“null”的参考。

How can I resolve?我该如何解决?

This is my code:这是我的代码:

Model Model

package me.lucacirfeta.model;
// default package

// Generated 29-lug-2020 10.31.08 by Hibernate Tools 4.3.5.Final

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Element generated by hbm2java
 */
@Entity
@Table(name = "ELEMENT", schema = "TEST")
public class Element implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 7331854204646419731L;
    
    private long id;
    private ElDate elDate;
    private Period period;
    private User user;
    private PlaceOfDiscovery placeOfDiscovery;
    private ElType elType;
    private ElDimension elDimension;
    private String description;
    private String otherDetails;
    private Date created;
    private boolean validation;
    private Date discoveryDate;
    
    private Set<ElementImage> elementImages = new HashSet<ElementImage>(0);

    public Element() {
    }

    @Id
    @Column(name = "ID", unique = true, nullable = false, precision = 22, scale = 0)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_DATE", nullable=false, insertable=false)
    public ElDate getElDate() {
        return this.elDate;
    }

    public void setElDate(ElDate elDate) {
        this.elDate = elDate;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_PERIOD", nullable=false, insertable=false)
    public Period getPeriod() {
        return this.period;
    }

    public void setPeriod(Period period) {
        this.period = period;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_USER", nullable=false, insertable=false)
    public User getUser() {
        return this.user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_PLACE_OF_DISCOVERY")
    public PlaceOfDiscovery getPlaceOfDiscovery() {
        return this.placeOfDiscovery;
    }

    public void setPlaceOfDiscovery(PlaceOfDiscovery placeOfDiscovery) {
        this.placeOfDiscovery = placeOfDiscovery;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_EL_TYPE", nullable=false, insertable=false)
    public ElType getElType() {
        return this.elType;
    }

    public void setElType(ElType elType) {
        this.elType = elType;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_EL_DIMENSION", nullable=false, insertable=false)
    public ElDimension getElDimension() {
        return this.elDimension;
    }

    public void setElDimension(ElDimension elDimension) {
        this.elDimension = elDimension;
    }

    @Column(name = "DESCRIPTION")
    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Column(name = "OTHER_DETAILS")
    public String getOtherDetails() {
        return this.otherDetails;
    }

    public void setOtherDetails(String otherDetails) {
        this.otherDetails = otherDetails;
    }

    @Column(name = "CREATED")
    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreated() {
        return this.created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    @Column(name = "VALIDATION", nullable = false, precision = 1, scale = 0)
    public boolean isValidation() {
        return this.validation;
    }

    public void setValidation(boolean validation) {
        this.validation = validation;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "DISCOVERY_DATE", length = 7)
    public Date getDiscoveryDate() {
        return this.discoveryDate;
    }

    public void setDiscoveryDate(Date discoveryDate) {
        this.discoveryDate = discoveryDate;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "element", cascade = {CascadeType.ALL})
    public Set<ElementImage> getElementImages() {
        return this.elementImages;
    }

    public void setElementImages(Set<ElementImage> elementImages) {
        this.elementImages = elementImages;
    }
    
}

Controller Controller

package me.lucacirfeta.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import me.lucacirfeta.model.Element;
import me.lucacirfeta.service.ElementService;
import me.lucacirfeta.service.ServiceException;

@Controller
@RequestMapping(value = "/admin/update/{id}")
public class AdminUpdateElementController {

    @Autowired
    private ElementService elementService;

    @GetMapping
    public ModelAndView updateElement(@PathVariable(name = "id") Long id) {
        Element element = null;

        try {
            element = elementService.findById(id);

        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }
        ModelAndView mv = new ModelAndView("updateElement");
        mv.addObject("element", element);
        
        return mv;
    }

    @PostMapping
    @RequestMapping(value = "/formUpdate")
    public String formUpdateElement(@ModelAttribute Element element) {

        try {
            this.elementService.update(element);
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/admin/elements";
    }

}

application.properties应用程序属性

# ===============================
# = DATA SOURCE
# ===============================

# Set here configurations for the database connection

# Connection url for the database "netgloo_blog"
spring.datasource.url= jdbc:****

# Username and password
spring.datasource.username= ****
spring.datasource.password= ****

spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver

# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1

# ===============================
# = JPA / HIBERNATE
# ===============================

# Show or not log for each sql query
spring.jpa.show-sql = false
spring.jpa.hibernate.format_sql= true

# Hibernate ddl auto (create, create-drop, update): with "update" the database
# schema will be automatically updated accordingly to java entities found in
# the project
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect

# ===============================
# = OTHERS
# ===============================

entitymanager.packagesToScan= me.lucacirfeta

server.port=8081

server.session.timeout=15

spring.mvc.hiddenmethod.filter.enabled=true

logging.level.org.springframework.web=DEBUG

html page html页面

<!DOCTYPE html>
<html lang="it" xmlns:th="http://www.thymeleaf.org">

<head>
    <div th:replace="header :: header"></div>
    <link th:href="@{/css/style.css}" rel="stylesheet" type="text/css" />
    <title th:text="Aggiorna + ' ' + Elemento + ' ' + ID + ' ' + ${element.id}"></title>
</head>

<body>

    <div th:insert="navbar :: navbar"></div>
    <h2 style="text-align: center;">Aggiorna Elemento</h2>
    <!--  Start of main body of record -->
    <div class="container-fluid" style="width: 60%;">
        <!--  Start of descriptive data -->
        <div class="row-fluid">
            <div>

                <form th:action="@{'/admin/update/' + ${element.id} + '/formUpdate'}" th:object="${element}"
                    th:method="post">

                    <!-- Header of section -->
                    <hr>
                    <p><strong>ID Univoco:</strong> <span th:text="${id}"></span></p>
                    <div class="form-group">
                        <h1 class="lead">Tipo</h1>
                        <input th:field="*{elType.elementType}" type="text" class="form-control" />
                    </div>
                    <!-- The description of the object -->
                    <div>
                        <div class="form-group">
                            <h4 class="lead">Descrizione</h4>
                            <textarea rows="5" th:field="*{description}" class="form-control"></textarea>
                        </div>
                    </div>
                    <p>
                    </p>
                    <!-- Others details -->
                    <div class="form-group">
                        <h4 class="lead">Altri dettagli</h4>
                        <textarea th:field="*{otherDetails}" class="form-control"></textarea>
                    </div>

                    <div class="container" style="display: flex; justify-content: space-between;">
                        <div class="row">
                            <div class="col">

                                <h4 class="lead">Cronologia</h4>
                                <p>
                                    Periodo dal: <input th:field="${element.Period.periodFrom}" class="form-control"
                                        type="text" />
                                    Periodo al: <input th:field="${element.Period.periodTo}" class="form-control"
                                        type="text" />
                                    Data dal: Circa AD <input th:field="${element.elDate.dateFrom}" class="form-control"
                                        type="text" />
                                    Data al: Circa AD <input th:field="${element.elDate.dateTo}" class="form-control"
                                        type="text" />

                                </p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col">

                                <h4 class="lead">Dimensioni e Peso</h4>
                                <p>
                                    Lunghezza: mm <input th:field="${element.elDimension.elLength}" class="form-control"
                                        type="text" />
                                    Peso: g. <input th:field="${element.elDimension.elWeight}" class="form-control"
                                        type="text" />
                                    Spessore: g. <input th:field="${element.elDimension.elThickness}"
                                        class="form-control" type="text" />
                                    Diametro: mm <input th:field="${element.elDimension.elDiameter}"
                                        class="form-control" type="text" />

                                </p>
                            </div>
                        </div>

                        <div class="row">
                            <div class="col">
                                <h4 class="lead">Materiale</h4>
                                <p>
                                    Materiale: <input th:field="${element.elType.material}" class="form-control"
                                        type="text" />
                                </p>
                            </div>
                        </div>
                    </div>

                    <div class="container" style="display: flex; justify-content: space-between;">
                        <div class="row">
                            <div class="col">
                                <h4 class="lead">Validazione</h4>
                                <p>
                                    <input th:field="${element.validation}" class="form-control" type="text" />
                                </p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col">
                                <h4 class="lead">User</h4>
                                <p>
                                    <input th:field="${element.user.id}" class="form-control" type="text" readonly />
                                    <input th:field="${element.user.username}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.firstName}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.lastName}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.password}" class="form-control" type="text"
                                        readonly />
                                </p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <button class="btn btn-primary" type="submit">Aggiorna</button>
                    </div>
                </form>
                <!-- End of descriptive data -->
            </div>
        </div>
    </div>
    <div th:insert="scripts :: scripts"></div>
</body>

</html>

For such situations it is best to create a simple DTO class like ElementDTO对于这种情况,最好创建一个简单的 DTO class 像 ElementDTO

public class ElementDTO {
    //all the fields that you need, getters, setters and default constructor
}

And then pass it to the update form by adding the following method in you controller然后通过在 controller 中添加以下方法将其传递给更新表单

@ModelAttribute("element")
public ElementDTO elementDTO(){
    return new ElementDTO();
}

This approach is better for several reasons:这种方法更好有几个原因:

  1. You don't need to load an object from your database in advance everytime the form is loaded每次加载表单时,您都不需要提前从数据库中加载 object
  2. You only need to define fields that you want to update and don't have to worry about hibernates rules on non-null fields.您只需要定义要更新的字段,而不必担心非空字段的休眠规则。

Then in the controlle method expecting the object you just change the parameter to (ElementDTO elementDTO) and copy all updated fields to the actial Element object that you then save in the database然后在期望 object 的控制方法中,您只需将参数更改为(ElementDTO elementDTO)并将所有更新的字段复制到实际元素 object 然后保存在数据库中

I found the solution.我找到了解决方案。

I use an Element in the session added with @SessionAttributes and no lost the references with User.我在 session 中使用了一个元素,添加了 @SessionAttributes,并且没有丢失用户的引用。

This is the edited controller:这是编辑后的 controller:

package me.lucacirfeta.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import me.lucacirfeta.model.Element;
import me.lucacirfeta.service.ElementService;
import me.lucacirfeta.service.ServiceException;

@Controller
@RequestMapping(value = "/admin/update/{id}")
@SessionAttributes(value = "element")
public class AdminUpdateElementController {

    @Autowired
    private ElementService elementService;

    @ModelAttribute("element")
    public Element updateElement(@PathVariable(name = "id") Long id) {

        Element element = null;

        try {
            element = elementService.findById(id);

        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return element;
    }

    @GetMapping
    public String updateElement() {
        return "updateElement";
    }

    @PostMapping
    @RequestMapping(value = "/formUpdate")
    public String formUpdateElement(Element element) {

        try {
            this.elementService.update(element);
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/admin/elements";
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Hibernate / Spring:Not-null属性引用null或transient值 - Hibernate/Spring: Not-null property references a null or transient value org.hibernate.PropertyValueException:非空属性在使用 Spring 引导时引用 null 或瞬态值 - org.hibernate.PropertyValueException: not-null property references a null or transient value while using Spring Boot not-null属性引用null或transient值? - not-null property references a null or transient value? 非空属性引用了一个瞬态值 Hibernate - Not-null property references a transient value Hibernate 非空属性引用了持久值的空值或瞬态值 - Not-null property references a null or transient value for persisted value 在Java SE中:not-null属性引用一个null或瞬态值 - In Java SE: not-null property references a null or transient value DataIntegrityViolationException:非null属性引用一个null或瞬态值 - DataIntegrityViolationException: not-null property references a null or transient value Hibernate + JPA:not-null属性引用一个null或瞬态值 - Hibernate + JPA: not-null property references a null or transient value not-null属性在Hibernate双向关系中引用null或瞬态值 - not-null property references a null or transient value in Hibernate bidirectional relationship 错误 - 非空属性引用 null 或瞬态值 - Error - not-null property references a null or transient value
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM