I want to join a single column from another table to one of my #Entity classes:
Currently it works as follows:
#Entity
public class Product {
#Id
private long id; //autogenerated
String type; //used for mapping
#ManyToOne
#JoinColumn(name = "type", insertable = false, updatable = false)
ProductMapping mapping;
}
#Entity
public class ProductMapping {
#Id
String type;
String longname;
}
Question: how could I replace the #ManyToOne mapping to directly map to String longname?
//TODO: how to directly map to 'mapping.longname'?
#JoinColumn(name = "type", insertable = false, updatable = false)
String mapping.longname;
You can use #Formula annotation with a query like this :
#Formula("(select pm.longname from product_mapping pm where pm.COL_NAME = value)")
private String longName;
//give the column name of type from product_mapping table
OR
You can also use the below approach :
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "type", referencedColumnName = "COL_NAME", insertable = false, updatable = false)
ProductMapping mapping;
The other entity use #NaturalId annotation on the field.
#Entity
public class ProductMapping {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
String type;
#NaturalId
#Column(name = "SOME_VALUE")
String longname;
}
Related
I have two java entity classes :
#Table(name = "user")
public class UserEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinColumn(name = "opportunity_id")
private OpportunityEntity opportunity;
}
and
#Table(name = "opportunity")
public class OpportunityEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToMany
#JoinColumn(name = "opportunity_id")
private List<UserEntity> users;
#OneToOne
#JoinColumn(name = "mainuser_id")
private UserEntity mainUser;
}
When i search for a list of Users [find users], i've got a "stackoverflow" when mapping User.opportunity.
the bug was clear that the opportunity.mainUser refer to User which itself refer to the same opportunity.
Is there another way to design my models ?
For example create a boolean isMain in User Model ?
Try to specify relationship to UserEntity by adding mappedBy to annotatation
#Table(name = "opportunity")
public class OpportunityEntity
{
#Id
#Column(name = "id", unique = true, nullable = false)
private Long id;
#OneToMany
#JoinColumn(name = "opportunity_id")
private List<UserEntity> users;
#OneToOne(mappedBy="opportunity")
#JoinColumn(name = "mainuser_id")
private UserEntity mainUser;
}
When saving my entities, child entities that work through the #OneToMany relationship are not saved to their tables. I can’t understand what’s the matter.
Employee:
#Entity
#Table(name = "EMPLOYEE", schema = PUBLIC)
public class Employee {
private String name;
private String lastname;
#OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, orphanRemoval = true)
List<EmployeePhoneNumber> employeePhoneNumbers = new ArrayList<>();
}
EmployeePhoneNumber:
#Entity
#Table(name = "EMPLOYEE_PHONES", schema = PUBLIC)
public class EmployeePhoneNumber {
#Id
#SequenceGenerator(allocationSize = 1, name = "SEQ_EMPLOYEE_PHONES", schema = PUBLIC,
sequenceName = "EMPLOYEE_PHONES_ID_SEQ")
#GeneratedValue(generator = "SEQ_EMPLOYEE_PHONES", strategy = GenerationType.SEQUENCE)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "employee_id", referencedColumnName = "id",
nullable = false, insertable = false, updatable = false)
private Employee employee;
#Column(name = "PHONE_NUMBER", unique = true, nullable = false)
private String phoneNumber;
#Enumerated(EnumType.STRING)
#Column(name = "NUMBER_TYPE", nullable = false)
private PhoneNumberType phoneNumberType;
}
How I set those fields and then save the entity:
EmployeePhoneNumber workPhone = new EmployeePhoneNumber();
workPhone.setPhoneNumber(workPhone);
workPhone.setPhoneNumberType(PhoneNumberType.WORK_PHONE);
EmployeePhoneNumber mobilePhone = new EmployeePhoneNumber();
mobilePhone.setPhoneNumber(mobilePhone);
mobilePhone.setPhoneNumberType(PhoneNumberType.MOBILE_PHONE);
EmployeePhoneNumber corporatePhone = new EmployeePhoneNumber();
corporatePhone.setPhoneNumber(corporatePhoneNumber);
corporatePhone.setPhoneNumberType(PhoneNumberType.CORPORATE_PHONE);
List<EmployeePhoneNumber> employeePhoneNumbers = employee.getEmployeePhoneNumbers();
employeePhoneNumbers.add(workPhone);
employeePhoneNumbers.add(mobilePhone);
employeePhoneNumbers.add(corporatePhone);
employee.setEmployeePhoneNumbers(employeePhoneNumbers);
employeeRepository.save(employee);
Upon completion of the method, I do not have a single error, everything works out correctly, only the tables are not filled - why?
You must also set the Employee reference in EmployeePhoneNumber because Hibernate will use this to save it.
workPhone.setEmployee(employee);
mobilePhone.setEmployee(employee);
corporatePhone.setEmployee(employee);
The best solution would be to create an addEmployeePhoneNumber method on the Employee like this:
public void addEmployeePhoneNumber(EmployeePhoneNumber phoneNumber) {
phoneNumber.setEmployee(this);
employeePhoneNumbers.add(phoneNumber);
}
That way you will not forget to set both sides of the relationship.
I'm having an issue with JPA and Hibernate. I have 2 classes (actually more but those are the 2 that are giving me a headache).
They have a OneToMany/ManyToOne relationship, and I have specified on the OneToMany that I want it to cascade every possible change (CascadeType.ALL).
However, when I let HBM2DDL run in "update" mode, it is creating foreign key constraints that are not fitting what I want to achieve. It is creating a constraint in RESTRICT mode, which is absolutely not what I have specified. Perhaps the error is in my code ? I've joined it below.
#Entity
public class Department {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false)
private String name;
#OneToMany(mappedBy = "departmentByDepartment", cascade = CascadeType.ALL)
private Collection<Article> productsById;
#OneToMany(mappedBy = "departmentByDepartment", cascade = CascadeType.ALL)
private Collection<User> usersById;
And then :
#Entity
#Table(name = "product", schema = "qlog_project", catalog = "")
public class Article {
#Id
#Column(name = "id", nullable = false)
private int id;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "description", nullable = false)
private String description;
#Column(name = "price", nullable = false)
private double price;
#Column(name = "image", nullable = false)
private String image;
#ManyToOne
#JoinColumn(name = "department", referencedColumnName = "id", nullable = false)
private Department departmentByDepartment;
#OneToMany(mappedBy = "productByProductId", cascade = CascadeType.ALL)
private Collection<Stock> stocksById;
Also, I cannot seem to be able to delete an Article instance with EntityManager.remove(). It's not producing any query and not doing anything. Maybe it is linked ?
Thanks in advance,
Regards
I have a database with several entities, in particular Book and User. Between them there exists a ManyToMany relationship like this:
Book:
#Entity
#Table(name = "Books")
public class Book implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "bookId", nullable = false, unique = true)
private Long id;
#Column(name = "title", nullable = false)
private String title;
#Column(name = "price", nullable = false)
private int price;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "bookId"),
inverseJoinColumns = #JoinColumn(name = "userId"))
private Set<UserAccount> users;
User:
#Entity
#Table(name = "UserAccounts")
public class UserAccount implements Serializable
{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.TABLE)
#Column(name = "userId", nullable = false, unique = true)
private Long id;
#Column(name = "username", nullable = false, unique = true)
private String username;
#Column(name = "password", nullable = false)
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name = "User_Book",
joinColumns = #JoinColumn(name = "userId"),
inverseJoinColumns = #JoinColumn(name = "bookId"))
Set<Book> purchasedBooks;
Everything works fine, the table User_Book is indeed created in the database. The problem seems to be related to the access of this Table.
For example,
Query query = entityManager.createQuery("SELECT u FROM User_Book u");
keeps telling me the following:
The abstract schema type 'User_Book' is unknown
So, shall I create from scratch the User_Book entity? Will it get automtically populated like now, that is, whenever a user buys a book, will this purchase be recorded in the table?
User_Book is not an entity. Therefore you cannot use createQuery, BUT you can use createNativeQuery to execute a SQL query:
Query query = entityManager.createNativeQuery("SELECT * FROM User_Book");
The result will be List<Object[]>
I have tried to create some JPA Entities for a DB designed with the following tables: PRINCIPALS and CREDENTIALS which have the following relations with other tables:
#Entity
#Table(name = "CREDENTIALS")
public class Credentials {
#Id
#Column(name = "CREDENTIAL_ID")
private Integer credentialID;
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
#OneToOne
#JoinColumn(name = "CREDENTIAL_TYPE_ID", insertable = false, updatable = false)
private CredentialTypes credentialTypes;
}
CREDENTIALS has a oneToOne relation with CREDENTIAL_TYPES
#Entity
#Table(name = "CREDENTIAL_TYPES")
public class CredentialTypes {
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
#Column(name = "DESCRIPTION")
private String description;
}
#Entity
#Table(name = "PRINCIPALS")
public class Principals implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Column(name = "PRINCIPAL_ID", nullable = false)
private String principalID;
#OneToOne
#JoinColumn(name = "PRINCIPAL_TYPE_ID", insertable = false, updatable = false)
private PrincipalTypes principalTypes;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "PRINCIPAL_CREDENTIAL",
joinColumns = #JoinColumn(name = "CREDENTIAL_ID"),
inverseJoinColumns = #JoinColumn(name = "PRINCIPAL_ID"))
private List<Credentials> credentials;
PRINCIPALS has a oneToOne relation with PRINCIPAL_TYPES
#Entity
#Table(name = "PRINCIPAL_TYPES")
public class PrincipalTypes implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Column(name = "DESCRIPTION")
private String description;
And finally PRINCIPALS has a oneToMany relation with CREDENTIALS and uses a join table PRINCIPLE_CREDENTIAL
#Entity
#Table(name = "PRINCIPAL_CREDENTIAL")
public class PrincipalCredential implements Serializable {
#Id
#Column(name = "PRINCIPAL_TYPE_ID", nullable = false)
private String principalTypeID;
#Id
#Column(name = "PRINCIPAL_ID", nullable = false)
private String principalID;
#Id
#Column(name = "CREDENTIAL_ID")
private Integer credentialID;
#Id
#Column(name = "CREDENTIAL_TYPE_ID")
private String credentialTypeID;
At startup (using SpringBoot) I receive an error for the oneToMany relation between Principals and Credentials and just don't have any idea how to fix it... Tried various other methods (The DB design cannot be changed).
Caused by: org.hibernate.AnnotationException: A Foreign key refering entities.Principals from entities.Credentials has the wrong number of column. should be 2
at org.hibernate.cfg.annotations.TableBinder.bindFk(TableBinder.java:502)
at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1467)
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1233)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:794)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:729)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:70)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1697)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1426)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1846)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:85
I find the exception wierd because there is no refering of Principlas from Credentials....
PRINCIPLE_TYPE_ID and CREDENTIAL_TYPE_ID are missing in the joinColumns/inverseJoinColumns. I think you must use the #JoinColumns Annotation