I have to map a composite PK with JPA in an Oracle DB.
I've followed other SO questions with relation to this tutorial but I'm still getting the following error:
java.sql.SQLSyntaxErrorException: ORA-00904: "COMPOSITEI0_"."NAME_1": Invalid Identifier (where NAME_1 relates to the name of one of the columns which are part of the PK)
This is my entity (real names not mentioned for data protection reasons):
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#Column(name = "NAME1")
private String name1;
#Column(name = "NAME2")
private String name2;
#Column(name = "NAME3")
private String name3;
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
public CompositePrimaryKeyTableEmbeddable getId() {
return this.id;
}
public void setId(CompositePrimaryKeyTableEmbeddable id) {
this.id = id;
}
// other getters and setters
My #Embeddable id class:
#Embeddable
public class CompositePrimaryKeyTableEmbeddable implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name="name1")
private String name1;
#Column(name="name2")
private String name2;
public CompositePrimaryKeyTableEmbeddable() {
super();
}
public CompositePrimaryKeyTableEmbeddable(String name1, String name2) {
this.name1 = name1;
this.name2 = name2;
}
My #Repository:
#Repository
public interface CompositeIdDao extends JpaRepository<CompositeIdEntity, CompositePrimaryKeyTableEmbeddable> {
}
And finally call to the DB, which only returns null because it's just a test to see if it all works together:
public CompositeIdEto saveCompositeId() {
CompositeIdEntity compositeIdEto = new CompositeIdEntity();
compositeIdEto.setname3("New");
compositeIdEto.setId(new CompositePrimaryKeyTableEmbeddable("ERR", "ER"));
this.compositeIdDao.save(compositeIdEto);
return null;
}
It seems you are duplicating the name1 and name2 columns by declaring them once
in the entity itself and later in the embeddable.
You seem to only need the id embeddable and the name3 declaration in the entity:
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
#Column(name = "NAME3")
private String name3;
Related
I have two classes, CarRentalCompany
#Entity
public class CarRentalCompany {
private static Logger logger = Logger.getLogger(CarRentalCompany.class.getName());
#Id
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<Car> cars;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<CarType> carTypes = new ArrayList<>(); //TODO: kan betere datastructuur zijn
/***************
* CONSTRUCTOR *
***************/
public CarRentalCompany()
{
// DEFAULT CONSTRUCTOR
}
public CarRentalCompany(String name, List<Car> cars) {
logger.log(Level.INFO, "<{0}> Car Rental Company {0} starting up...", name);
setName(name);
this.cars = cars;
for(Car car:cars)
carTypes.add(car.getType());
}
...
}
and CarType
#Entity
public class CarType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private String name;
private int nbOfSeats;
private boolean smokingAllowed;
private double rentalPricePerDay;
//trunk space in liters
private float trunkSpace;
/***************
* CONSTRUCTOR *
***************/
public CarType()
{
}
public CarType(String name, int nbOfSeats, float trunkSpace, double rentalPricePerDay, boolean smokingAllowed) {
this.name = name;
this.nbOfSeats = nbOfSeats;
this.trunkSpace = trunkSpace;
this.rentalPricePerDay = rentalPricePerDay;
this.smokingAllowed = smokingAllowed;
}
When running the application, it throws the following exception:
NucleusFatalUserException: Attempt to assign child with key
"CarType(6614661952700416)" to parent with key
"CarRentalCompany("Hertz")". Parent keys are immutable
What do I need to do to get the key of the CarType right?
You are not persisting your CarRentalCompany entity before adding CarType entity. See a
similar thread here. The persist operation must be used only for new entities. An entity is new when it has never been associated with a database row, meaning that there is no table record in the database to match the entity in question.
I'm working with a hierachy object model with a jpa entity persistance support.
Here the classes model:
User class:
#Entity
#Table(name = "user", catalog = "users")
#NamedQueries({
#NamedQuery(...
})
#Inheritance(strategy= InheritanceType.JOINED)
#DiscriminatorColumn(name = "apType", discriminatorType =
DiscriminatorType.STRING, length = 255)
//#DiscriminatorValue("user")
public class User implements Serializable {
#Transient
protected PropertyChangeSupport changeSupport = new
PropertyChangeSupport(this);
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Column(name = "apType")
private String apType;
#Basic(optional = false)
#Column(name = "name")
private String name;
public UsuariDeClaus() {
this.setApType("user");
}
public Long getId() {
return id;
}
public void setId(Long id) {
Long oldId = this.id;
this.id = id;
changeSupport.firePropertyChange("id", oldId, id);
}
public String getApType() {
return apType;
}
public void setApType(String apType) {
this.apType = apType;
}
public String getName() {
return name;
}
public void setName(String name) {
String oldName = this.name;
this.name = name;
changeSupport.firePropertyChange("name", oldName, name);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
changeSupport.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener
listener) {
changeSupport.removePropertyChangeListener(listener);
}
}
ApplicationUser class :
#Entity
#Table(name = "applicationuser", catalog = "usuweb793")
#NamedQueries({
#NamedQuery(...
})
public class ApplicationUser extends Users{
#Basic(optional = false)
#Column(name = "nickname", unique=true)
private String nickname;
#Basic(optional = false)
#Column(name = "password")
private String password;
public ApplicationUser() {
super.setApType("ApplicationUser");
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
String oldPassword = this.password;
this.password = password;
changeSupport.firePropertyChange("password", oldPassword, password);
}
public String getNickname() {
return user;
}
public void setNickname(String nickname) {
String oldNickname = this.nickname;
this.nickname = nickname;
changeSupport.firePropertyChange("nickname", oldNickname, nickname);
}
}
and administratorUser class:
#Entity
#Table(name = "administratoruser", catalog = "usuweb793")
#NamedQueries({
#NamedQuery(...})
public class AdministratorUser extends AplicationUser{
public AdministratorUser() {
super.setApType("administratoruser");
}
}
The entity manager creates on mysql database 4 tables:
sequence, user, aplicationuser and administratoruser.
user table:
id name aptype
1 aaa user
2 bbb aplicationuser
3 ccc administratoruser
aplicationuser table:
id nickname password
2 bbbxxxx bbbyyyyy
3 cccxxxx cccyyyyy
administratoruser table:
id
3
Is possible to change the user priviligies without remove an object and create a new one ?
(i would like the id not to change)
Something like:
User user = em.find(1);
New AplicattionUser(user);
user table:
id name aptype
1 aaa aplicationuser
2 bbb aplicationuser
3 ccc administratoruser
aplicationuser table:
id nickname password
1 aaaxxx aaayyyyy
2 bbbxxxx bbbyyyyy
3 cccxxxx cccyyyyy
administratoruser table:
id
3
According to what I understand and from my POV, if Application and Administrator are just roles for Userthat you can switch between .... remove the inheretence, make a User entity and Role entity -with a corresponding table and join between the two entities with the appropriate join -OneToOne or OneToMany according to to your business case- ..... If you can't change the database/the code ... there is a "dirty" solution (and "dirty" again) that you might try ... make a native bulk update statement to make the change you need but be aware of the following :
1- I am nit sure if it will work, you need to try it
2- You must be sure that the entity is not managed by any persistence context at the time of running
3- You are responsible for refreshing the entity / persistence context/ cache after the update
I will select all the columns from #Embeddable Class Certification. But i cann't select it. how can i do select the Embeddable class.
#Entity
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
#ElementCollection
#CollectionTable(name = "Certification", joinColumns = {#JoinColumn(name="user_id")})
private List<Certification> certifications = new ArrayList<Certification>();
public List<Certification> getCertifications() {
return certifications;
}
public void setCertifications(List<Certification> certifications) {
this.certifications = certifications;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
.....
#Embeddable Class Certification
#Embeddable
public class Certification{
private String name;
private String certArt;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCertArt() {
return certArt;
}
public void setCertArt(String certArt) {
this.certArt = certArt;
}
......
If i run the ResultService i get the following exception:
Caused by: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select c from Certification c]. Unknown entity type [Certification].
How can i select the #Embeddable Class?
You would need to retrieve Certification via the real Entity class i.e. Department. One example query could be as below:
select cer from Department dep join dep.certifications cer
Alternatively, you may want to retrieve qualifying Department entities and then fetch certifications using them.
I am new to hibernate and having a tough time trying to wrap my head around setting up Joined inheritance with composite Primary Key. With my current setup, I get a:
JDBCException: could not insert: LandHolidayPackage
I am essentially looking for two things:
Are the inheritance annotations in place ?
Is the composite PK setup properly ?
DB Design:
Reference
Here are my classes and the annotations involved:
#Entity
#Table(name = "HOLIDAYPACKAGE")
public final class HolidayPackage {
private Integer idPackage;
private String name;
private Set<HolidayPackageVariant> holidayPackageVariants = new HashSet<HolidayPackageVariant>(0);
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "IDHOLIDAYPACKAGE", nullable = false)
public Integer getIdPackage() {
return idPackage;
}
#OneToMany(fetch=FetchType.LAZY, cascade={CascadeType.ALL}, mappedBy = "holidayPackage")
public Set<HolidayPackageVariant> getHolidayPackageVariants() {
return holidayPackageVariants;
}
// ommitted other part of the code
}
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#Table(name="HOLIDAYPACKAGEVARIANT")
public abstract class HolidayPackageVariant {
private Integer idHolidayPackageVariant;
private HolidayPackage holidayPackage;
private String typeHolidayPackage;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="IDHOLIDAYPACKAGEVARIANT", nullable=false)
public Integer getIdHolidayPackageVariant() {
return idHolidayPackageVariant;
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDHOLIDAYPACKAGE", nullable=false)
public HolidayPackage getHolidayPackage() {
return holidayPackage;
}
#Column(name="TYPEHOLIDAYPACKAGE", nullable=true)
public String getTypeHolidayPackage() {
return typeHolidayPackage;
}
// ommitted setters, equals hashCode
}
#Entity
#Table(name="LANDHOLIDAYPACKAGEVARIANT")
public final class LandHolidayPackageVariant extends HolidayPackageVariant{
private static final String LAND = "LAND";
protected LandHolidayPackageVariant() {}
public LandHolidayPackageVariant(HolidayPackage holidayPackage) {
super(holidayPackage, LAND);
}
}
#Entity
#Table(name="FLIGHTHOLIDAYPACKAGEVARIANT")
public final class FlightHolidayPackageVariant extends HolidayPackageVariant{
private static final String FLIGHT = "FLIGHT";
private Destination originCity;
protected FlightHolidayPackageVariant(){}
public FlightHolidayPackageVariant(HolidayPackage holidayPackage,
Destination originCity) {
super(holidayPackage, FLIGHT);
setOriginCity(originCity);
}
#ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.ALL})
#JoinColumn(name="IDDESTINATION", nullable=false)
public Destination getOriginCity() {
return originCity;
}
// ommited other setters etc functions
}
You annotated the properties in stead of the fields. JPA by default tries to access the fields. If you want JPA to use the fields you have to annotate the class with #AccessType(AccessType.Field).
I am trying to map the following table
CREATE TABLE Person (
p_id varchar(255) not null,
p_name varchar(255 not null,
p_post_code varchar(12) not null,
primary key (p_id, p_name),
);
Usually when i map an Entity to the above table i would do something like this (for single column primary keys):
private int p_id;
private String p_name;
private String p_post_code;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id")
public Long getPId() {
return p_id;
}
public void setPId(int p_id) {
this.p_id = p_id;
}
#Column(name="p_name")
public String getPname() {
return p_name;
}
public void setPname(String string) {
this.p_name = string;
}
#Column(name="p_post_code")
public String getPostCode() {
return p_post_code;
}
public void setPostCode(String string) {
this.p_post_code = string;
}
The above works if the primary key is a single column (i.e. p_id) and the value for this column is generated in the database.
How would i modify the above to map it so that both p_id and p_name are the primary key.
Also, how would this work, if the composite key is a foreign key in another table.
I am trying to google for some examples but i cant find a simple example and most seem to be using the XML based configuration.
When using composite keys with JPA you need to use an embedded class as an id.
In your case you would have a person class and a primary key class for person:
#entity
public class Person
{
#EmbeddedId
private PersonPK key;
#Column(name="p_post_code", nullable = false)
private String p_post_code;
//....
}
#Embeddable
public class PersonPK
{
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id");
private Long p_id;
#Column(name="p_name")
private String p_name;
public PersonPK(String name)
{
p_name = name;
}
//....
}
Using a class for the person's name (so the name is also a foreign key):
#entity
public class Person
{
#EmbeddedId
private PersonPK key;
#MapsId(value="p_name_id")
#ManyToOne
#JoinColumn(name = "p_name_id", referencedColumnName = "id")
private Name p_name;
#Column(name="p_post_code", nullable = false)
private String p_post_code;
//....
}
#Embeddable
public class PersonPK
{
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="p_id");
private Long p_id;
#Column(name="p_name_id")
private Long p_name_id;
public PersonPK(Name name)
{
p_name_id = name.getId();
}
//....
}
#Entity
public class Name
{
#Id
#GeneratedValue(some generation strategy here)
#Column(name="id")
private Long id;
#Column(name="name")
private String name;
//....
}