I am trying to set up our database in our project. But I get some errors, when I try to use #ManyToOne and#OneToMany on a #MappedSuperclass Entity:
#MappedSuperclass
public abstract class Person extends Model{
//public abstract class Person {
// ATTRIBUTES
#Column(columnDefinition = "varchar(20) not null")
private String firstName;
#Column(columnDefinition = "varchar(20) not null")
private String lastName;
#Column(columnDefinition = "varchar(20) not null")
private String password;
#Column(columnDefinition = "varchar(50) not null")
private String eMail;
#Column(columnDefinition = "varchar(8) not null")
private String svn;
private static int staticId = 0; // Identifier, staticId is unique.
#Id
#Column(columnDefinition = "integer not null")
private int id;
#Column(columnDefinition = "integer")
private int age;
#Column(columnDefinition = "varchar(10)")
private String telephoneNumber;
#Column(columnDefinition = "decimal(10,2)")
private double salary;
#Column(columnDefinition = "boolean")
private boolean allowedOvertime;
//#OneToMany(mappedBy = "person")
private List<TimeEntryMonth> listTimeEntryMonth;
#OneToMany(mappedBy = "person")
private List<Vacation> listVacation;
#OneToMany(mappedBy = "person")
private List<SickLeave> listSickLeave;
One of the classes who extends from Person:
#Entity
public class Employee extends Person {
// ATTRIBUTES
private String position;
private Boss boss;
And one of the #OneToMany relations:
public class SickLeave extends Model {
/* ATTRIBUTES */
#Id
private int id;
#ManyToOne
private Person person;
private int personIdSL;
private String reason;
If I compile my whole Project without the #ManyToOne and #OneToMany, it will work fine. But with the it will lead into som errors:
Error injecting constructor, java.lang.RuntimeException: Error reading
annotations for models.SickLeave
I tried to delete the abstract and replaced #MappedSuperclass with #Entity and the project works. So I think that I cant have #OneToMany and #ManyToOne relations on a #MappedSuperclass, But I dont want to refactor my whole project
Is there any (easier) way to handle such issues?
Thank you.
Person is not an Entity, so you can't use OneToMany to it. You will need to make Person an Entity or point to Employee, which seems to make more sense to me.
Related
I've got following two tables:
Customer
id
name
Order
id
product_name
customer_id
with a 1 to 1 relation
and java entities:
#Data
public class Customer{
#Id
private Long id;
private String name;
}
#Data
public class Order{
#Id
private Long id;
#Column("id")
private Customer customer; //i want to somehow map this
private String productName;
}
and a controller
#Controller
public class MyController{
//...
#GetMapping("/")
public String getmap(Model m){
System.out.println(repository.findAll()) //prints "nullrows" due to wrong sql statement
return "mytemplate";
}
}
my current issue is, that spring is executing following sql statement:
SELECT Order.id, Order.product_name, Customer.id, Customer.name
FROM Order LEFT OUTER JOIN Customer ON Customer.id = Order.id
what i actually want is to join on Customer.id = Order.customer_id while leaving the classes as they are i.e. the customer reference needs to stay in order.
i've tried every annotation that i could find so far and have made no progress.
EDIT:
I am not allowed to use jpa/hibernate
One workaround is to do the following:
#Data
public class Customer{
#Id
private Long id;
private String name;
}
#Data
public class Order{
#Id
private Long customerId;
private Long id;
#Column("id")
private Customer customer; //i want to somehow map this
private String productName;
}
causing this to automatically join on Customer.id = Order.customer_id
This does not look like a good fix however.
You can use #OneToOne and #JoinColumn annotations for your One-to-One relationship:
#Data
public class Customer{
#Id
#Column(name = "id")
private Long id;
#Column(name = "name")
private String name;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id", referencedColumnName = "id")
private Order order;
}
#Data
public class Order{
#Id
#Column(name = "id")
private Long id;
#Column(name = "product_name")
private String productName;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id", referencedColumnName = "id")
private Customer customer;
}
I have a to make a one-to-one association between two Entities, but one of them must have two #Id. One is PRI another one is MUL. How must i declare composite id, and how do i need to map the classes?
#Entity
#Table(name = "PERSONS")
public class Person implements Serializable{
private static final long serialVersionUID = -3451407520028311143L;
#Id
#Column(name = "ID")
private Integer id;
#Column(name = "ADDRESS_ID")
private Integer addressId;
#Column(name ="NAME")
private String name;
#OneToOne(mappedBy= "person", cascade= CascadeType.ALL)
private Address address;
...
}
second class is mapped via #IdClass annotation
#Entity
#Table ( name = "ADDRESS" )
#IdClass(AddressKeys.class)
public class Address implements Serializable {
#Id
#Column ( name = "ID")
private Integer id;
#Id
#Column ( name = "PERSON_ID")
private Integer idPerson;
#Column ( name = "CITY" )
private String city;
#OneToOne(cascade= CascadeType.ALL)
#JoinColumn(name="PERSON_ID")
private Person person;
...
}
and the id class
class AddressKeys implements Serializable{
private Integer id;
private Integer idPerson;
//getters and setters
#Override
public int hashCode() {
...
return result;
}
#Override
public boolean equals(Object obj) {
...
}
}
So when i try to create and save a record i have a next error
Could not open sessionRepeated column in mapping for entity:
hibernateMappedModels.base1.mappedClasses.oneToOne.Address column:
PERSON_ID (should be mapped with insert="false" update="false")
java.lang.NullPointerException at
hibernateMappedModels.base1.Main.run(Main.java:45) at
hibernateMappedModels.base1.Main.main(Main.java:24
I tryed to make an Id fields unInsertable and unUpdatable, and it was working, but i need them to be insertable and updatable; Is there any possibility to do it?
I am confused by your mappings and not sure what is required other then the simple mappings below: if I am missing something then you will need to expand on your question. You are getting the error as you have mapped the column twice - once via the one-to-one and once as a simple property. Additionally, I am not sure why you require a composite key on address.
#Entity
#Table(name = "PERSONS")
public class Person implements Serializable{
private static final long serialVersionUID = -3451407520028311143L;
#Id
#Column(name = "ID")
private Integer id;
#Column(name ="NAME")
private String name;
#OneToOne(mappedBy= "person", cascade= CascadeType.ALL)
private Address address;
}
#Entity
#Table ( name = "ADDRESS" )
public class Address implements Serializable {
#Id
#Column ( name = "ID")
private Integer id;
#Column ( name = "CITY" )
private String city;
#OneToOne(cascade= CascadeType.ALL)
#JoinColumn(name="PERSON_ID")
private Person person;
}
I have class User:
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable
private List<Role> roles;
}
Class Owner inherits from User
#Entity
public class Owner extends User {
private String pesel;
private String adress;
#OneToMany(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private List<Pet> pets;
}
and Owner had Pet
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
#ManyToOne
private Owner owner;
}
Why when starting the application gets the error:
org.springframework.data.mapping.PropertyReferenceException: No
property user found for type Pet!
--EDIT
First I have version, which was as follows:
now I try to share User instance to a doctor and the owner of the animal
The problem is that I do not know whether I am doing the mapping , and therefore wanted to ask whether it must look like
--edit2
I've simplified the scheme just a bit to better illustrate what happens
--edit3
Currently my Object's was presented:
#Entity
public class Pet {
#Id
#GeneratedValue
private Integer id;
private String name;
private String weight;
}
User
#Entity
public class User {
#Id
#GeneratedValue
private Integer id;
private String name;
private String password;
#ManyToMany
#JoinTable(name="user_roles")
private List<Role> roles;
}
PetOwner
#Entity
public class PetOwner extends User {
private String pesel;
private String adress;
#OneToMany(mappedBy="petOwner")
private List<Pet> pets;
}
I replace
#ManyToOne
private PetOwner petOwner;
for
#ManyToOne
private Owner petOwner;
and it works. Do you have a PetOwner class?
Also provide the log error to get more information about it
I can't make my foreign keys auto generate using hibernate and jpa with annotations. Everything seems ok, The entries are saved in database. All the date come from one form which, when submited creates an User object with ModelAttribute and then saves it in Database.
Here are my beans. Anything else i should add ?
#Entity
#Table(name="adress")
public class Adress implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="adress_id")
private Integer adressId;
#NotBlank(message="The city must be completed")
#Column(name="city")
#Size(min=5,max=30)
private String city;
#NotBlank(message="The street must be completed")
#Column(name="street")
#Size(min=5,max=30)
private String street;
#NotNull(message="The street number must be completed")
#NumberFormat
#Column(name="street_no")
private Integer streetNo;
#OneToOne
#JoinColumn(name="user_id")
private User user;}
and the other one:
#Entity
#Table(name="users")
public class User implements Serializable {
#Id
#Column(name="user_id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer userId;
#NotBlank(message="Username can't be blank")
#Size(min=5,max=30)
#Column(name="username")
private String username;
#NotBlank(message="Password field can't be blank")
#Size(min=5,max=30)
#Column(name="password")
private String password;
#NumberFormat
#NotNull(message="Age field must not be blank")
#Column(name="age")
private Integer age;
#Column(name="message")
#Size(min=0,max=100)
private String message;
#Column(name="date")
#DateTimeFormat(pattern="dd/mm/yyyy")
private Date dateCreated;
#OneToOne(mappedBy="user",cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private Adress adress;
+getters and setters for them
public void save(T entity){
sessionFactory.getCurrentSession().save(entity);
}
If I understand you correctly and you're trying to get Hibernate to set the foreign key on your related record this might help. Try getting rid of mappedBy and instead specify the JoinColumn. This works for me on a one to many:
The order:
#Entity
#Table(name = "`order`")
public class Order implements Serializable {
#Id
#GeneratedValue
private Long id;
// Order columns...
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "order_id")
private Set<Item> items;
}
The item:
#Entity
#Table(name = "item")
public class Item implements Serializable {
#Id
#GeneratedValue
private Long id;
// Item columns...
#ManyToOne(optional = false)
#JoinColumn(name = "order_id", referencedColumnName = "id", nullable = false)
private Order order;
}
in adress class
#OneToOne(mappedBy="adress")
private User user;
and in user class
#OneToOne(cascade=CascadeType.ALL,fetch=FetchType.EAGER,optional=false)
#PrimaryKeyJoinColumn
private Adress adress;
I am new to JPA and doing a small sample to learn about it.
But I got one problem below, please help me out, and please explain why:
I have class Customer.java, which is mapped to table customer in db:
#Entity
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "id_customer")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
// accountNumber field maps with accountNumber column in Account table
#Column(name = "loginId", unique = true)
private String loginId;
#Column(name = "password")
private String password;
#Column(name = "firstName")
private String firstName;
#Column(name = "lastName")
private String lastName;
#Column(name = "address")
private String address;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(mappedBy="customer")
private List<Account> accountList;
#OneToMany(mappedBy="customer")
private List<Card> cardList;
// getters and setters goes here
}
The above class has two lists, accountList and cardList, their generic Class (Card and Account) extends BaseInfo using Single table Inheritance.
Here is my BaseInfo.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "discriminator", discriminatorType = DiscriminatorType.STRING)
public class BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "number")
private String number;
#Column(name = "availableNumber")
private Long availableNumber;
//getter and setter here
}
Class Card.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue(value = "C")
public class Card extends BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "cardType")
private String cardType;
#ManyToOne
#JoinColumn(name = "id_customer")
private Customer customer;
//getter and setter
}
And class Account.java:
#Entity
#Table(name = "account")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorValue(value = "A")
public class Account extends BaseInfo implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "accountName")
private String accountName;
#Column(name = "accountType")
private String accountType;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "dt_created")
private Date createdDate;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "dt_lst_updt")
private Date lastUpdatedDate;
#ManyToOne
#JoinColumn(name = "id_customer")
private Customer customer;
//getter, setter
}
Then, I do a query that query customer from database with loginid and password, like this:
entityTransaction.begin();
TypedQuery<Customer> query = entityManager.createQuery(
"SELECT c FROM " + Customer.class.getName()
+ " c Where c.loginId= :loginId", Customer.class);
query.setParameter("loginId", loginId);
res = query.getSingleResult();
entityTransaction.commit();
The code run with no error, but the result is somethings strange to me: When I debug (or print out the result to jsp), accountList or cardList contains all Account of that customer, just like they don't care about the 'discriminator' column.
I have 2 questions:
How can I archive the goal that listCard contains only Card (discrimination = c) and listAccount contains only Account (discriminator = a) ?
Is there an alternative way to query listCard or listAccount without query the customer first (like I use) ??
Thank in advance! :D
I'm not sure if it's a JPA restriction or a Hibernate-specific restriction, but you may not use the same column to map two different associations.
You should use something like car_customer_id to map the association between customer and cards, and account_customer_id to map the association between customer and accounts.