【问题标题】:add data to database (related tables) Spring Boot将数据添加到数据库(相关表) Spring Boot
【发布时间】:2018-12-16 20:54:15
【问题描述】:

我的英语不好,但我试图描述我的问题。 我是春天的新人。我在向我的数据库中添加数据时遇到了一些问题。我必须列出 Pc 和 Pc 特征。它们按 ID 相关。在非关联表中添加数据很容易,但是如何在相关表中添加数据?我应该在我的控制器中写什么?下面有一些类。

电脑类:

@Entity
@Table(name = "pc")
public class Pc {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;

private String name;
private int price;

public Pc(){}

public Pc(String name, int price) {
    this.name = name;
    this.price = price;
}

@OneToMany
@JoinColumn(name = "pc_id")
private List<PcChars> chars = new ArrayList<>();

public List<PcChars> getChars() {
    return chars;
}

public void setChars(List<PcChars> chars) {
    this.chars = chars;
}

public int getId() {
    return id;
}

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

public String getName() {
    return name;
}

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

public int getPrice() {
    return price;
}

public void setPrice(int price) {
    this.price = price;
}

PcChars 类:

@Entity
@Table(name = "pcChars")
public class PcChars {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;


private String name;
private String value;



public PcChars(){}

public PcChars(String name, String value) {
    this.name = name;
    this.value = value;
}

@ManyToOne
private Pc pc;



public Pc getPc() {
    return pc;
}

public void setPc(Pc pc) {
    this.pc = pc;
}

public int getId() {
    return id;
}

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

public String getName() {
    return name;
}

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

public String getValue() {
    return value;
}

public void setValue(String value) {
    this.value = value;
}

PcCharactsController:

@Controller
public class PcCharactsController {

final private PcRepo pcRepo;
final private PcCharRepo pcCharRepo;

public PcCharactsController(PcRepo pcRepo, PcCharRepo pcCharRepo) {
    this.pcRepo = pcRepo;
    this.pcCharRepo = pcCharRepo;
}

//Pc characteristics list
@GetMapping("pc/{id}/")
public String pcCharList(@PathVariable int id, Model model) throws Exception{

    Pc pc = pcRepo.findById(id).orElseThrow(() -> new Exception("PostId " + 
id + " not found"));
    List<PcChars> pcChars = pc.getChars();
    model.addAttribute("model", pc.getName());
    model.addAttribute("pcChars", pcChars);
    return "charList";
}

//add characteristic
@PostMapping("pc/{id}/")
public String addCharact(){

    return "charList";
}

Characteristics.ftl:

<html>
<head>
<title>Ho</title>
</head>
   <body>
    <div>
       <form method="post" action="/pc/${id}/">
          <input type="text" name="name">
          <input type="text" value="value">
          <input type="hidden" name="pc_id" value="${id}">
          <button type="submit">Add</button>
       </form>
    </div>
  </body>
</html>

【问题讨论】:

    标签: java hibernate spring-boot


    【解决方案1】:

    由于您没有使用任何modelAttribute 将输入值直接绑定到 POJO,您可以使用简单的HttpServletRequest 来获取输入属性,使用它们来创建您想要存储的对象并使用 Hibernate 存储它

    @PostMapping("pc/{id}/")
    public String addCharact(HttpServletRequest req){
      String name = req.getParameter("name");
      String value = req.getParameter("value");
      String id = req.getParameter("id");
      PcChars pcchars = new PcChars(name,value,id); // create the corresponding constructor
      SessionFactory sessionFactory;
      Session session = sessionFactory.openSession();
      Transaction tx = null;
        try{
            tx = session.getTransaction();
            tx.begin();
            session.save(pcchars);
            tx.commit();
        }
        catch (HibernateException e) {
            if (tx!=null) tx.rollback();
            e.printStackTrace();
        } finally {
            session.close();
        }
      return "charList";
    }
    

    【讨论】:

    • 感谢您的回答。但是我没有带有 pc_id 参数的构造函数,因为它没有在我的类中定义为字段。这只是@JoinColumn 参数。如何将它添加到构造函数中?还是不可能?
    • 在这种情况下,首先获取具有相应 id 的 PC (f.e Pc pc = pcRepo.findByID(id) ),然后创建一个 PcChars 实例,如 PcChars pcchars = new PcChars(name,value,pc) ; (您应该首先在 PcChars 类中创建一个构造函数,例如 public PcChars(String name, String value, Pc pc) { this.name = name; this.value = value; this.pc = pc; } 最后按照描述存储对象以上
    【解决方案2】:

    您正在使用的 Spring 部分称为 Spring data,这是一个允许您在 Spring 应用程序中使用 JPA 的库。 JPA 是一种称为 ORM(对象关系映射)的框架规范。

    为简单起见,在您的代码中,您不再使用关系方法,而是使用对象方法。您在类的字段上添加的注释用于定义它们与您的数据库表和字段之间的映射。

    因此,您不必再分别插入两个实体。您需要创建一个 Pc 实例,然后创建一个 PcChars 实例,最后将字符添加到 pc 的字符列表中,如下所示:

    Pc myPc = new Pc();
    PcChars myChars = new PcChars();
    myPc.getChars().add(myChars);
    

    当你使用你的存储库来保存修改时:

    pcRepo.save(myPc);
    

    JPA 实现会自动为您完成工作:

    • 在 PC 表中插入与您的 PC 实例对应的行
    • 在 PC_CHARS 表中插入与您的 PC 字符对应的行
    • 将 PC_CHARS.PC_ID 设置为新插入的 PC 实例 ID 的 ID,以便在它们之间创建引用。

    不确定,但我认为当您将字符添加到 pc 实例时,ORM 也会这样做:

    myChars.setPc(myPc);
    

    为了使两个实例之间的界限互惠。

    请注意,我根据您的架构使用了任意字段名称。

    【讨论】:

      【解决方案3】:

      我强烈建议您在使用@OneToMany 关系时将关系责任交给子方。

      修改你的父类如下:

      @OneToMany(cascade = CascadeType.ALL, mappedBy="pc")
      @BatchSize(size = 10)
      private List<PcChars> chars = new ArrayList<>();
      
      public void addPcChar(PcChar pcChar) {
          this.chars.add(pcChar);
          pcChar.setPc(this);
      }
      

      关于子类:

      @ManyToOne
      @JoinColumn(name = "pc_id")
      private Pc pc;
      

      现在你可以像下面这样坚持你的父母和孩子:

      Pc pc = new Pc();
      PcChar pcChar = new PcChar();
      pc.addPcChar(pcChar);
      

      如果你使用spring boot数据仓库,它会正确保存如下

      // assume your repository like below
      public interface PcRepository extends CrudRepository<Pc, Integer> {}
      
      // in your service or whatever in some place
      pcRepository.save(pc);
      

      通过保存休眠实体管理器:

      EntityManagerFactory emfactory = 
      Persistence.createEntityManagerFactory("Hibernate");
      
      EntityManager entitymanager = emfactory.createEntityManager();
      
      entitymanager.getTransaction().begin();
      entitymanager.persist(pc);
      entitymanager.getTransaction().commit();
      
      entitymanager.close();
      emfactory.close();
      

      有关休眠关系的详细信息,请查看我的帖子:https://medium.com/@mstrYoda/hibernate-deep-dive-relations-lazy-loading-n-1-problem-common-mistakes-aff1fa390446

      【讨论】:

      • 感谢您的回答。按照您的建议,我已经更改了我的 POJO 课程。但是我怎样才能将pc_id 请求为@RequestParameter 我的特征?或者还有其他方法可以将 pc_id 插入表中?我想象它是这样的:@PostMapping("pc/{id}/") public String addCharact(@RequestParam int id, @RequestParam String name, @RequestParam String value, Model model){ CONSTRUCTOR return "charList"; } 但我无法创建没有 pc_id 的构造函数。希望你能理解我。
      • 你想在哪里做这个?通过 PostMapping 在您的控制器中?
      • 是的。我想通过 PostMapping 在我的控制器中执行此操作。
      猜你喜欢
      • 2018-08-14
      • 2020-05-31
      • 2011-05-11
      • 1970-01-01
      • 1970-01-01
      • 2013-10-24
      • 2018-04-28
      • 2020-02-12
      • 1970-01-01
      相关资源
      最近更新 更多