i'm trying to build a simple full stack tic-tac-toe application, but i've some problem defing a one-to-many relationship.
here the context, we have a main table Games:
CREATE TABLE `tictactoe`.`games` (
`idgames` INT NOT NULL AUTO_INCREMENT,
`gridConf` VARCHAR(45) NOT NULL,
`playerNum` VARCHAR(45) NOT NULL,
PRIMARY KEY (`idgames`));
and a secondary table, Gamesteps:
CREATE TABLE `tictactoe`.`gamesteps1` (
`idgamesteps` INT NOT NULL AUTO_INCREMENT,
`idgame` INT NOT NULL,
`step` VARCHAR(45) NOT NULL,
PRIMARY KEY (`idgamesteps`));
i'd like to define a relation One (Game) to Many (Gamesteps),
where the combo Gamesteps.idgamesteps and Gamesteps.games is primary key on the Gamesteps table.
i have two doubts:
1- how should i define my db tables? are my queries rights or do i need an explict foreing key?
2 -JPA annotations:
here my entities:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Games {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idgames;
private String gridConf;
private Integer playerNum;
#OneToMany(mappedBy = "idgames")
private Set<GameSteps> gameSteps;
//all setter/getters
secondary table:
import javax.persistence.Entity;
import javax.persistence.Id;
#Entity
public class GameSteps {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idGameSteps;
#ManyToOne
#JoinColumn(name = "idgames", referencedColumnName = "idgames")
private Integer idgame;
private String step;
//all setter/getter
i'm trying to archive is the possibility to do a Save/findAll operation throught my CRUDRepository interface on the main entity (Games) and do an automatic Save/findAll on all the others subEntities (gamesteps).
for me is not clear where i should use the #OneToMany or #ManyToOne annotations.
For now i'm only getting exceptions.
if needs others info just ask, any type of help / documentation will be really approciated!
Thanks!
Following #Smutje comment i've change to:
public class GameSteps {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idGameSteps;
#ManyToOne
#JoinColumn(name = "idgames", referencedColumnName = "idgames")
private **Games** idgame;
and
#OneToMany(mappedBy = "**idgame**")
private Set<GameSteps> gameSteps;
but got:
java.sql.SQLSyntaxErrorException: Unknown column 'idgames' in 'field list'
If you want Gamesteps.idgamesteps and Gamesteps.games to be primary key on the Gamesteps table. You have to use the tags #EmbeddedId and #Embeddable, your composite key has to be another class.
The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with #EmbeddedId and contains an instance of that embeddable class.
Something like this
import javax.persistence.*;
#Entity
public class GameSteps {
#EmbeddedId
private GameStepsPK pk;
private String step;
// getters and setters
GameStepsPK would be the composite key
import java.io.Serializable;
import javax.persistence.*;
#Embeddable
public class ExploitationEvaluationPK implements Serializable {
private static final long serialVersionUID = 1L;
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer idGameSteps;
#ManyToOne
#JoinColumn(name = "idgames", referencedColumnName = "idgames")
private Games idgames;
You can also read about this here
I hope this helps
Related
I am using spring boot and jpa to create the table but I need to create table without #Id primary key column.It is not giving me to make the table without this #Id field. How to get this using spring data jpa?
LetterDoc.java
package com.ashwin.springsecurityangular.model;
import java.io.Serializable;
import javax.persistence.CascadeType;
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.Table;
import com.fasterxml.jackson.annotation.JsonIgnore;
#Entity
#Table(name = "letter_doc")
public class LetterDoc implements Serializable {
private static final long serialVersionUID = 1L;
#ManyToOne(fetch = FetchType.EAGER, optional = false,cascade=CascadeType.PERSIST)
#JoinColumn(name = "letterNo")
#JsonIgnore
private Letter letter;
#ManyToOne(fetch = FetchType.EAGER, optional = false,cascade=CascadeType.PERSIST)
#JoinColumn(name = "documentId")
#JsonIgnore
private Document document;
private String docFile;
//i omitted getters and setters and both constructor
}
It ask me the #Id field need.So there is error like:
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: No identifier specified for entity: com.ashwin.springsecurityangular.model.LetterDoc
In this table i am avoided to make #Id field but it is not giving me.How to achieve this?
JPA Specification clearly narrates that an Entity class must have a unique, immutable ID. However there are some hacks you can give them a try.
1) Maintain UUID for this purpose.
#Id
#Column(columnDefinition = "BINARY(16)")
private UUID uuid;
2) Create a DTO/POJO representation of data fields in view layer, then execute a SQL Native query, then map the result set to your class
USE JPA PROJECTIONS
In your case you dont have a primary key so use JpaProjections to get the fields you want
first declare Entity as
#Entity
#Immutable
set your Repository
public interface AddressView {
String getZipCode();
}
Then use it in a repository interface:
public interface AddressRepository extends Repository<Address, Long> {
#Query("SELECT ADDRESS from TABLE WHERE address = ?1")
AddressView getAddressByState(String state);
}
note ADDRESS entity in above is a placeholder
just make it
Public class ADDRESS{
#Id
Long id;
I am using MySQL database.
In my table i there are two four primary keys, out of which one is auto incremented.
#Embeddable
public class EmployeeId implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name = "id", nullable = false)//
This is just Pk in mysql table
**private int id;**
// I have tried and #GeneratedValue(strategy = GenerationType.IDENTITY),
#GeneratedValue(strategy = GenerationType.IDENTITY)
//and #GeneratedValue(strategy = GenerationType.TABLE)
//#GeneratedValue(strategy = GenerationType.AUTO, generator = "id") #SequenceGenerator(name = "id", sequenceName = "id")
**this is auto incremented and pk in mysql table**
#Column(name = "gender_key", nullable = false)
private int gender_key;
}
#Entity
#Table(name = "employee")
public class employee {
#EmbeddedId
private EmployeeId employeeId;
private String emp_name;
private String mobile_no;
employee() {
}}
public interface employeeRepository extends
JpaRepository<employee, EmployeeId> {
}
In My Controller I want id after employeeRepository.save(bean); method because i want to save that id in different db .
logger.info("gender_key is --- > "+gender_key);
But I am getting always 0 value of gender_key.
The thing which I have tried is:
bean = employeeRepository.save(bean)
int gender_key= bean.getGender_key();
logger.info("gender_keyis --- > "+gender_key);
But still the value for gender_key is 0(Zero).
Or any Query which I have to write in repository .
How I can get the auto incremented value of gender_key which is inserted into MySQL table?
Please Help.
Thanks in advance.
Your JPA #Id does not need to match the database PK column(s). So long as it is unique then that is all that matters.
From https://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing:
The JPA Id does not always have to match the database table primary
key constraint, nor is a primary key or a unique constraint required.
As your an auto-increment column is guaranteed to be unique then just use gender_key as your #ID and map id as a normal column.
#Entity
#Table(name = "employee")
public class employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int genderKey;
#Column
private int id;
}
To be honest I would find your schema confusing however.
I would also suggest reading the following:
https://www.javatpoint.com/java-naming-conventions
You're missing a #GeneratedValue at the id field.
Depending on its values, you're free to choose a strategy for generation, like a sequences, id tables, an automatic internal id generation.
Last but not least GenerationType.AUTO will choose one of the mentioned strategies.
See the Javadocs for javax.persistence.GeneratedValue and javax.persistence.GenerationType.
I have the following relationship with person and transaction (one to one in my case). I want to be able to save a Person with a Transaction attached resulting in two inserts. One in tbl_person and one in tbl_Transaction. But the following only generates one insert instead of two. The one insert is in tbl_Transaction:
`CREATE TABLE `tbl_person` (
`ID` char(36) NOT NULL,
`TransactionID` int(11) DEFAULT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `TransactionID` (`TransactionID`),
CONSTRAINT `tbl_person_ibfk_1` FOREIGN KEY (`TransactionID`)
REFERENCES `tbl_Transaction` (`TransactionID`)
);
CREATE TABLE `tbl_transaction` (
`TransactionID` int(11) NOT NULL,
PRIMARY KEY (`TransactionID`)
);
#Table(name="tbl_person")
#Entity
#JsonIgnoreProperties(ignoreUnknown = true)
#ToString
#Data
public class Person {
#Id
#GeneratedValue(generator = "hibernate-uuid")
#GenericGenerator(name = "hibernate-uuid", strategy = "uuid2")
#Column(name="ID", nullable = false)
private String ID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "transactionId")
private Transaction transaction;
}
#Table(name="tbl_transaction")
#Entity
#Data
public class Transaction {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer transactionId;
}
public class Service() {
public void saveTransaction(Transaction transaction) {
Person person = new Person();
person.setTransaction(transaction);
getSessionCurrent().save(person);
}
}
`
service.saveTransaction(transaction);
The service.saveTransaction returns with no exception but it only inserts the transaction but not the person.
Can any one tell me what I am doing wrong ??
you need to define a #OneToOne field in Transaction class
like specified in this question:
#OneToOne bidirectional mapping with #JoinColumn
and then add this line:
transcation.setPerson(person);
I have two classes like this
package models;
import java.util.*;
import javax.persistence.*;
import play.db.jpa.*;
#Entity
#Table(name = "commitment_type_value")
public class CommittmentTypeValue extends Model{
#Id
#Column(name = "id", nullable = false)
public Long id;
#Column(name = "value", nullable = true)
public String type;
#ManyToOne
#JoinColumn(name="commitment_type_id")
public CommitementType commitmentType;
public CommittmentTypeValue(){
}
}
-------------
package models;
import java.util.*;
import javax.persistence.*;
import play.db.jpa.*;
/**
*
* #author hatem
*/
#Entity
#Table(name = "commitment_type")
public class CommitementType extends Model{
#Id
#Column(name = "id", nullable = false)
public Long id;
#Column(name = "type", nullable = true)
public String type;
#OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, mappedBy="commitmentType")
public List<CommittmentTypeValue> commitmentTypeValues;
public CommitementType(){
}
}
when I execute my app, this problem appears :
A JPA error occurred (Unable to build EntityManagerFactory): A Foreign
key refering models.CommitementType from models.CommittmentTypeValue
has the wrong number of column. should be 2
Please, can Any one tell me what 's wrong ?
Please check your foreign key column name it should match the exactly with the name of column.
EDIT
If your problem is still unsolved then please check if your persistance.xml has
<property name="generateDdl" value="true" />
and if it already have then check if you are getting any error in generation of table.
If yes then clear the data in table
or
add drop-and-create-tables option in config file
or
change your code as follows
#ManyToOne(optional=true)
#JoinColumn(name="commitment_type_id", nullable = true)
public CommitementType commitmentType;
Because you might have old data in table which might be stopping the creation of new table.
Reference column name is missing in your many to one join in class CommittmentTypeValue
#ManyToOne
#JoinColumn(name="commitment_type_id" referencedColumnName="id" )
public CommitementType commitmentType;
Also specify target entity
#OneToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL, targetEntity=CommittmentTypeValue.class, mappedBy="commitmentType")
public List<CommittmentTypeValue> commitmentTypeValues;
The error sounds like you Id in CommitementType is composite, so your foreign key must contain two columns.
Include the code for the CommitementType.
This question already has answers here:
Mapping ManyToMany with composite Primary key and Annotation:
(2 answers)
Closed 7 years ago.
I have the following classes in my JPA model (getters, setters, and irrelevant fields omitted):
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Currency {
#Id
private Integer ix;
}
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Product {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
}
I need to define a class Price, such that when the DDL is generated from the classes, the primary key of the corresponding table is composed of the keys for Product and Currency. I've tried the following:
#Entity #Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#IdClass(PricePK.class)
public class Price {
#Id #ManyToOne(optional = false)
private Product product;
#Id
#ManyToOne(optional = false)
private Currency currency;
}
#Embeddable
public class PricePK implements Serializable {
Integer product;
Integer currency;
}
But this generates the following for the PRICE table:
create table PRICE (
currency_id int null,
product_id int null,
primary key (currency_id, product_id)
);
Notice that both currency_id and product_id are nullable, which causes the following error when I try to load the DDL into SQL Server
Cannot define PRIMARY KEY constraint on nullable column in table 'PRICE'
I don't understand why these are nullable, because in the domain model they are annotated
#ManyToOne(optional = false)
The DDL is generated using the org.hibernate.dialect.SQLServerDialect SQL dialect.
Recently I created ManyToMany relation using Composite Primary key and annotation as bi directional #OneToMany. This code works flawless. Maybe it will help:
Mapping ManyToMany with composite Primary key and Annotation:
Since you are using #IdClass, the PricePK class need not be marked with the #Embeddable
annotation. An example is given in http://www.java2s.com/Code/Java/JPA/SetIdClassforCompoundKey.htm
I tried your code removing the #Embeddable on PricePK class, and the price table generated in MYSQL database with not null fields.
Following is how you could use #EmbeddedId to achieve the required result:
(getters and setters omitted)
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Price {
#EmbeddedId
PricePK pricePk;
}
#Embeddable
public class PricePK implements Serializable {
#ManyToOne(optional = false)
private Product product;
#ManyToOne(optional = false)
private Currency currency;
}