DenProg
DenProg

Reputation: 23

add data to database (related tables) Spring Boot

I know English badly, but i'm trying to describe my problem. I'm new in Spring. And I have some problems with adding data to my database.I have to table Pc and Pc characteristics. They are related by Id. It's easy to add data in non realted table, but how can I add data in related table? What shoud I write in my Controller? There are some classes below.

Pc class:

@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 class:

@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>

Upvotes: 2

Views: 2545

Answers (3)

Emre Savcı
Emre Savcı

Reputation: 3070

I strongly suggest you to give responsibility of relationship to child side when using @OneToMany relation.

Modify your parent class as below:

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

On the child class:

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

Now you can persist your parent with child as below :

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

If you use spring boot data repository, it saves it correctly as below

// assume your repository like below
public interface PcRepository extends CrudRepository<Pc, Integer> {}

// in your service or whatever in some place
pcRepository.save(pc);

With saving hibernate entity manager:

EntityManagerFactory emfactory = 
Persistence.createEntityManagerFactory("Hibernate");

EntityManager entitymanager = emfactory.createEntityManager();

entitymanager.getTransaction().begin();
entitymanager.persist(pc);
entitymanager.getTransaction().commit();

entitymanager.close();
emfactory.close();

For detailed information about hibernate relationship take a look at my post : https://medium.com/@mstrYoda/hibernate-deep-dive-relations-lazy-loading-n-1-problem-common-mistakes-aff1fa390446

Upvotes: 1

NickAth
NickAth

Reputation: 1112

Since you are not using any modelAttribute to bind the input values straight to a POJO you can use simple HttpServletRequest to get the input attributes, use them to create the object you want to store and store it using 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";
}

Upvotes: 1

Fabien LH
Fabien LH

Reputation: 76

The part of Spring you're using is called Spring data, a library that allows you to use JPA in your Spring application. JPA is a specification for frameworks called ORM (Object-relationnal mapping).

To keep it simple, in your code, you do not use the relational approach anymore, but an object approach. Annotations you put on your classes' fields are used to define mappings between them and your database tables and fields.

So, you don't have to insert both entities separately anymore. You need to create a Pc instance, then to create a PcChars one, and finally to add the chars into the pc's chars list, like this :

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

And when you'll use your repository to save the modifications with this :

pcRepo.save(myPc);

The JPA implementation will automatically do the work for you :

  • Inserting the row corresponding to your PC instance in the PC table
  • Inserting the row corresponding to your PC chars in the the PC_CHARS table
  • Settings the PC_CHARS.PC_ID with the ID of the freshly inserted PC instance's id in order to create the reference between them.

Not sure, but I think the ORM also do this when you add your chars to the pc instance :

myChars.setPc(myPc);

in order to make the bound between both instances reciprocal.

Note that I used arbitrary field names according to your schema.

Upvotes: 1

Related Questions