【问题标题】:Spring Boot Data JPA detached entity passed to persist on @OneToMany and @OneToOne传递给 @OneToMany 和 @OneToOne 的 Spring Boot Data JPA 分离实体
【发布时间】:2021-04-19 01:12:41
【问题描述】:

问题

我正在尝试在我的 Postgres 数据库中存储一个对象。这由 Order.class、(List) OrderDevice.class 和 Department.class 组成。

重要的是 OrderDevices 总是新存储在数据库中,但部门可能已经存在。 当我尝试使用 save 将对象保存到我的数据库时,我收到以下错误消息:(如下所示)

如果部门尚不存在,我收到错误消息“分离的实体传递给坚持:com.niclas.model.OrderDevice”,如果部门存在,错误消息如下所示:“分离的实体传递给坚持:com .niclas.model.Department”。

解决方案尝试

  1. This solution 不能使用,因为我不使用双向映射。 (我不想使用双向映射,因为我想在没有订单的情况下访问部门。)
  2. 我还尝试将 Cascade 类型更改为 MERGE like in this solution
  3. 我也尝试在方法上使用@Transactional
  4. 我还尝试先将子项保存在数据库中,然后再将父项保存为这样:

departmentRepository.save(order.getDepartment()); orderDeviceRepository.saveAll(order.getDevices()); orderRepository.save(order);

我希望我的描述已经足够好,并且我对解决方案的建议感到高兴

错误日志 日志可以查看here。 (格式在这里不起作用)

订单类

@Entity
@Table(name = "orders")
public class Order extends AuditModel {

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;

@Column(name = "order_id")
private String orderId;

@Column(name = "department_id")
private long departmentId;

@OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "department", referencedColumnName = "id")
private Department department;

@JsonProperty("deviceList")
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinColumn(name = "order_id", referencedColumnName = "order_id")
private List<OrderDevice> devices;

@JsonProperty("forename")
@Column(name = "sender_forename")
private String senderForename;

@JsonProperty("surname")
@Column(name = "sender_surname")
private String senderSurname;

@Column(name = "notes", columnDefinition = "TEXT")
private String notes;

@Column(name = "month")
private int month;

@Column(name = "year")
private int year;

public Order() {
}


... Getter/Setters
}

OrderDevice.class

@Entity
@Table(name = "order_devices")
public class OrderDevice extends AuditModel{

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;


@Column( name = "order_id", insertable = false, updatable = false )
private String orderId;


@Column(name = "device_id")
private long deviceId;

@Column(name = "device_name")
private String deviceName;

@Column(name = "priceName")
private String priceName;

@Column(name = "price")
private double price;

@Column(name = "count")
private int count;

public OrderDevice() {
}

... Getters/Setters
}

部门.class

@Entity
@Table(name = "departments")
public class Department {

//TODO add Form Validation
//TODO better Naming for From Attributes on Frontend and Backend

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO) //TODO better config for GenerationType
private long id;

@Column(name = "department_name")
private String department;

@Column(name = "contact_person_forename")
private String forename;

@Column(name = "contact_person_surname")
private String surname;

@Column(name = "contact_person_mail")
private String mail;

@Column(name = "street")
private String street;

@Column(name = "house_number")
private String houseNumber;

@Column(name = "location")
private String location;

@Column(name = "postal_code")
private int postalCode;

@Column(name = "country")
private String country;

@Column(name = "auto_send_invoice")
private boolean autoSend;

@Column(name = "registered")
private boolean registered;


public Department() {
}

... Getter/Setters
}

OrderController.class

@Slf4j
@RestController
public class OrderController {

private final DepartmentRepository departmentRepository;

private final OrderRepository orderRepository;

private final OrderDeviceRepository orderDeviceRepository;


public OrderController(OrderRepository orderRepository, DepartmentRepository departmentRepository, 
OrderDeviceRepository orderDeviceRepository) {
    this.orderRepository = orderRepository;
    this.departmentRepository = departmentRepository;
    this.orderDeviceRepository = orderDeviceRepository;
}


@PostMapping("/orders/add")
public ResponseEntity<Order> addDepartment(@RequestBody Order order) throws JsonProcessingException {

    order.setOrderId(order.generateOrderId());

    DateTime dateTime = new DateTime();
    order.setMonth(dateTime.getMonthOfYear());
    order.setYear(dateTime.getYear());

    order.getDevices().forEach(orderDevice -> {
        orderDevice.setOrderId(order.getOrderId());
    });
     
    
    //departmentRepository.save(order.getDepartment());
    //orderDeviceRepository.saveAll(order.getDevices());
    orderRepository.save(order);
    return new ResponseEntity<>(order, HttpStatus.CREATED);
}

更新

如果以这种方式创建对象,则不会发生错误,并且订单将成功保存在数据库中。 但是,我不明白为什么它以这种方式工作,而不是通过 ObjectMapper。有谁知道为什么?

@PostMapping("/orders/add")
public ResponseEntity<Order> addDepartment(@RequestBody JsonNode jsonNode) throws JsonProcessingException {
    
    Order order = new Order();

    JsonNode departmentJson = jsonNode.get("department");
    Department department;
    if ( departmentJson.get("id").canConvertToInt() ) {
        department = departmentRepository.findDepartmentById(departmentJson.get("id").asInt());
    } else {
        department = new Department();
        department.setDepartment(departmentJson.get("department").asText());
        department.setForename(departmentJson.get("forename").asText());
        department.setSurname(departmentJson.get("surname").asText());
        department.setMail(departmentJson.get("mail").asText());
        department.setStreet(departmentJson.get("street").asText());
        
        department.setHouseNumber(departmentJson.get("houseNumber").asText());
        department.setLocation(departmentJson.get("location").asText());
        department.setPostalCode(departmentJson.get("postalCode").asInt());
        department.setCountry(departmentJson.get("country").asText());
        department.setAutoSend(departmentJson.get("autoSend").asBoolean());
        
    department.setRegistered(departmentJson.get("registered").asBoolean());
    }
    order.setDepartment(department);
    
    order.setOrderId(order.generateOrderId());
    order.setDepartmentId(department.getId());

    List<OrderDevice> orderDevices = new ArrayList<>();
    JsonNode devices = jsonNode.get("deviceList");
    for (JsonNode node : devices) {
        //TODO replace this mess with objectMapper
        if (node.has("count") && node.get("count").asInt() != 0){
            OrderDevice device = new OrderDevice();
            device.setOrderId(order.getOrderId());
            device.setDeviceId(node.get("id").asLong());
            device.setDeviceName(node.get("deviceName").asText());
            device.setPriceName(node.get("priceName").asText());
            device.setPrice(node.get("price").asDouble());
            device.setCount(node.get("count").asInt());
            orderDevices.add(device);
        }
    }
    order.setDevices(orderDevices);

    order.setSenderForename(jsonNode.get("forename").asText());
    order.setSenderSurname(jsonNode.get("surname").asText());
    order.setNotes(jsonNode.get("notes").asText());

    DateTime dateTime = new DateTime();
    order.setMonth(dateTime.getMonthOfYear());
    order.setYear(dateTime.getYear());

    orderRepository.save(order);
    return new ResponseEntity<>(order, HttpStatus.CREATED);
}

【问题讨论】:

  • in addDepartment 这些设备是否真的有任何 id 或者它们的 id 是否为空?
  • @CholNhial 设备有 ID

标签: java spring database model spring-data-jpa


【解决方案1】:

你可以尝试用orderRepository.save(order)代替orderRespostiory.saveOrUpdate(order)

【讨论】:

    猜你喜欢
    • 2018-01-05
    • 1970-01-01
    • 2015-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-02
    • 1970-01-01
    • 2015-07-10
    相关资源
    最近更新 更多