使用 jpa 将数据插入到 2 个连接表中

Posted

技术标签:

【中文标题】使用 jpa 将数据插入到 2 个连接表中【英文标题】:inserting data to 2 joined tables using jpa 【发布时间】:2021-11-01 17:27:56 【问题描述】:

我是 sring boot 和 jpa 的新手,所以我正在尝试制作一个采用 cutomer 类和电话号码类的 api

客户:

package com.phonenumbers.phonenumbers.entity;

import com.fasterxml.jackson.annotation.JsonIdentityReference;
import javax.persistence.*;

@Entity
@Table(name = "customer")
public class Customer 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(name = "c_name", nullable = false)
    private String name;
    @Column(name = "c_address", nullable = false)
    private String address;
    @OneToOne(targetEntity = Phonenumber.class,mappedBy = "customer", cascade = CascadeType.ALL)
    private Phonenumber phone;

    public Customer() 

    

    @Override
    public String toString() 
        return "Customer" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                ", phone=" + phone +
                '';
    

    public long getId() 
        return id;
    

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

    public String getName() 
        return name;
    

    public void setName(String name) 
        this.name = name;
    

    public String getAddress() 
        return address;
    

    public void setAddress(String address) 
        this.address = address;
    

    public Phonenumber getPhone() 
        return phone;
    

    public void setPhone(Phonenumber phone) 
        this.phone = phone;
    

    public Customer( String name, String address, Phonenumber phone) 

        this.name = name;
        this.address = address;
        this.phone = phone;
    

电话号码:

package com.phonenumbers.phonenumbers.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "phonenumber")
public class Phonenumber 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(name = "p_number", nullable = false)
    private String number;
    @Column(name = "c_code", nullable = false)
    private String ccode;
    @Column(name = "c_name", nullable = false)
    private String cname;
    @Column(name = "o_name", nullable = false)
    private String oname;

    public Phonenumber()  

    public Phonenumber(String number, String ccode, String cname, String oname) 
        super();
        this.number = number;
        this.ccode = ccode;
        this.cname = cname;
        this.oname = oname;
    

    public long getId() 
        return id;
    
    public void setId(long id) 
        this.id = id;
    

    public String getNumber() 
        return number;
    
    public void setNumber(String number) 
        this.number = number;
    

    public String getCcode() 
        return ccode;
    
    public void setCcode(String ccode) 
        this.ccode = ccode;
    

    public String getCname() 
        return cname;
    
    public void setCname(String cname) 
        this.cname = cname;
    

    public String getOname() 
        return oname;
    
    public void setOname(String oname) 
        this.oname = oname;
    

    @Override
    public String toString() 
        return "Phonenumber [id=" + id + ", number=" + number + ", ccode=" + ccode + ", cname=" + cname + ", oname="
                + oname + "]";
    

客户控制器:

package com.phonenumbers.phonenumbers.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import com.phonenumbers.phonenumbers.entity.Customer;
import com.phonenumbers.phonenumbers.repository.CustomerRepository;

@RestController
@RequestMapping("/api/v1")
@CrossOrigin
public class CustomerController 
    @Autowired
    private CustomerRepository customerrepository;

    @GetMapping("/customer1")
    public List<Customer> getAllCustomers() 
        return customerrepository.findAll();
    

    @GetMapping("/customer6/id")
    public Optional<Customer> getcustomerById(@PathVariable(value = "id") Long customerid) 
        return customerrepository.findById(customerid);
    

    @PostMapping("/customer")
    public Customer create (@RequestBody Customer newcustomer) 
        return customerrepository.save(newcustomer);
    

//    @PutMapping("/customer3/id")
//    public ResponseEntity<Customer> update(@PathVariable(value = "id") Long customerid,
//                                           @RequestBody Customer numberDetails)
//        Customer x = customerrepository.getById(customerid);
//
//        x.setName(numberDetails.getName());
//        x.setAddress(numberDetails.getAddress());
//        x.setPhoneid(numberDetails.getPhoneid());
//
//        final Customer updatedcustomer = customerrepository.save(x);
//        return ResponseEntity.ok(updatedcustomer);
//    
    @DeleteMapping("/customer2/id")
    public Map<String, Boolean> delete(@PathVariable(value = "id") Long customerid) 
        Customer u = customerrepository.getById(customerid);
        customerrepository.delete(u);
        Map<String, Boolean> response = new HashMap<>();
        response.put("deleted", Boolean.TRUE);
        return response;
    


电话号码控制器:

package com.phonenumbers.phonenumbers.controller;

import java.util.HashMap;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.phonenumbers.phonenumbers.entity.Phonenumber;
import com.phonenumbers.phonenumbers.repository.PhoneNumberRepository;

@SuppressWarnings("unused")
@RestController
@RequestMapping("/api/v1")
public class PhonenumberController 
    @Autowired
    private PhoneNumberRepository phonenumberrepository;

    @GetMapping("/phonenumber")
    public List<Phonenumber> getAllPhonenumbers() 
        return phonenumberrepository.findAll();
    

    @GetMapping("/phonenumber/id")
    public ResponseEntity<Phonenumber> getnumberById(@PathVariable(value = "id") Long numberid) 
        Phonenumber t = phonenumberrepository.getById(numberid);
        return ResponseEntity.ok().body(t);
    
    @PostMapping("/phonenumber6")
    public Phonenumber create(@RequestBody Phonenumber pnumber) 
        return phonenumberrepository.save(pnumber);
    

    @PutMapping("/phonenumber1/id")
    public ResponseEntity<Phonenumber> update(@PathVariable(value = "id") Long numberid,
                                              @RequestBody Phonenumber numberDetails)
        Phonenumber x = phonenumberrepository.getById(numberid);

        x.setNumber(numberDetails.getNumber());
        x.setCcode(numberDetails.getCcode());
        x.setCname(numberDetails.getCname());
        x.setOname(numberDetails.getOname());

        final Phonenumber updatednumber = phonenumberrepository.save(x);
        return ResponseEntity.ok(updatednumber);
    
    @DeleteMapping("/phonenumber2/id")
    public Map<String, Boolean> delete(@PathVariable(value = "id") Long numberid) 
        Phonenumber u = phonenumberrepository.getById(numberid);
        phonenumberrepository.delete(u);
        Map<String, Boolean> response = new HashMap<>();
        response.put("deleted", Boolean.TRUE);
        return response;
    
    PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();

所以我需要帮助才能知道如何在数据库中插入客户和电话号码,并在客户和电话号码之间建立连接关系,我也遇到了这个错误:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unknown mappedBy in: com.phonenumbers.phonenumbers.entity.Customer.phone, referenced property unknown: com.phonenumbers.phonenumbers.entity.Phonenumber.customer
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1786) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154) ~[spring-context-5.3.9.jar:5.3.9]
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:908) ~[spring-context-5.3.9.jar:5.3.9]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.9.jar:5.3.9]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.4.jar:2.5.4]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-2.5.4.jar:2.5.4]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) ~[spring-boot-2.5.4.jar:2.5.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) ~[spring-boot-2.5.4.jar:2.5.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) ~[spring-boot-2.5.4.jar:2.5.4]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) ~[spring-boot-2.5.4.jar:2.5.4]
    at com.phonenumbers.phonenumbers.PhonenumbersApplication.main(PhonenumbersApplication.java:15) ~[classes/:na]
Caused by: org.hibernate.AnnotationException: Unknown mappedBy in: com.phonenumbers.phonenumbers.entity.Customer.phone, referenced property unknown: com.phonenumbers.phonenumbers.entity.Phonenumber.customer
    at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:171) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1693) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1661) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1224) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1255) ~[hibernate-core-5.4.32.Final.jar:5.4.32.Final]
    at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:58) ~[spring-orm-5.3.9.jar:5.3.9]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:365) ~[spring-orm-5.3.9.jar:5.3.9]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:409) ~[spring-orm-5.3.9.jar:5.3.9]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.afterPropertiesSet(AbstractEntityManagerFactoryBean.java:396) ~[spring-orm-5.3.9.jar:5.3.9]
    at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.afterPropertiesSet(LocalContainerEntityManagerFactoryBean.java:341) ~[spring-orm-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1845) ~[spring-beans-5.3.9.jar:5.3.9]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1782) ~[spring-beans-5.3.9.jar:5.3.9]
    ... 16 common frames omitted

Process finished with exit code 1

【问题讨论】:

实体Phonenumber 上没有字段customer,但@OneToOne 注释中的mapedBy = "customer" 暗示了这一点。我建议阅读有关该主题的教程,例如this one over at Baeldung. 所以即使是单向连接? 如果是单向的,那么有@OneToOne注解的那一边一定是拥有那一边。情况并非如此,因为没有定义 @JoinColumn 并且设置了 mappedBy-attribute。请阅读我在first comment 中链接的教程。 【参考方案1】:

使用以下映射:

@Entity
@Table(name = "customer")
public class Customer 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @Column(name = "c_name", nullable = false)
    private String name;
    @Column(name = "c_address", nullable = false)
    private String address;
    @ManyToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "phone_id")
    private Phonenumber phone;

【讨论】:

以上是关于使用 jpa 将数据插入到 2 个连接表中的主要内容,如果未能解决你的问题,请参考以下文章

使用 html 表单将数据插入到 wordpress 表中

如何在 php pdo 中使用 1 个表单将数据插入到 2 个不同的表中?

如何使 Kafka 接收器连接器在接收器启动时将数据从主题插入到表中

Spring data jpa 插入多个表以避免锁定表

如何从 3 个不同的表中插入内连接

如何在 JPA 中构造插入查询