I have a couple of entities mixed with Embedded attributes. I've been able to override embedded column names using #AttributeOverrides and #AttributeOverride but it doesn't seem to work for nested entities.
see below:
#Entity
#Table(name = "branch")
public class Branch {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String phoneNumber;
private String email;
#Embedded
#AttributeOverrides({
#AttributeOverride( name = "streeNumber", column = #Column(name = "branch_street_number")),
#AttributeOverride( name = "streetName", column = #Column(name = "branch_street_name")),
#AttributeOverride( name = "lga", column = #Column(name = "branch_lga_id")),
#AttributeOverride( name = "city", column = #Column(name = "branch_city"))
})
private Location location;
Location entity:
#Embeddable
public class Location {
private String streetNumber;
private String streetName;
#ManyToOne
#JoinColumn(referencedColumnName = "id", nullable = false)
private LocalGovernmentArea lga;
private String city;
the lga column still generates as lga_id instead of branch_lga_id
Is there any solution to this?
Thank you.
Found a solution. I can override the entity name using #AssociationOverrides
#Embedded
#AttributeOverrides({
#AttributeOverride( name = "streetNumber", column = #Column(name = "branch_street_number")),
#AttributeOverride( name = "streetName", column = #Column(name = "branch_street_name")),
#AttributeOverride( name = "lga", column = #Column(name = "branch_lga_id")),
#AttributeOverride( name = "city", column = #Column(name = "branch_city"))
})
#AssociationOverrides({
#AssociationOverride(
name = "lga", joinColumns = #JoinColumn(name = "branch_lga_id"))
})
private Location location;
That does the trick!
Related
I have a table with n x n relationship. That means i have a code that is repeated with only a "brand" column being different between them. The code is not the ID.
I need to have one distinct class that contains all repeatable values and with a list that has all the unique brand column values.I cannot show most of the code samples because of my company security policies. But the entity below is a mock of what i'm seeking.
`
#Entity
#Table(name = "Table")
public class Teste {
#Column(name = "CODE", insertable = false, updatable = false)
private String code;
#Column(name = "NAME")
private String name;
#Column(name = "BRAND")
private String brand;
#OneToMany(cascade = CascadeType.ALL)
#JoinTable(name = "BRAND", joinColumns = { #JoinColumn(name = "CODE"), #JoinColumn(name = "BRAND")})
private Set<Model> brands = new HashSet<>();
#Column(name = "UPDATE_DATE")
private Date update_date;
#Column(name = "EDITOR")
private String editor;
#Id
#Column(name = "ID")
private int id;
}
`
I have the following code for many to many or many to one relationship persistence using Spring JPA.
This is my repository test https://github.com/Truebu/testJpa.git
This class has three one-to-many relationships, but none work well
#Entity(name = "routine_assignament")
#Table(name = "routine_assignament")
public class RoutineAssignament {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "date_start",nullable = true,columnDefinition = "DATE")
private Date date_start = new Date();
#Column(name = "date_end",nullable = true,columnDefinition = "DATE")
private Date date_end;
#ManyToOne
#JoinColumn(name = "id_user")
private User user;
#ManyToOne
#JoinColumn(name = "id_routine")
private Routine routine;
#OneToMany(mappedBy = "routine_assignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routine_assignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
The other classes
#Entity(name = "score")
#Table(name = "score")
public class Score {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "commentary",nullable = false,columnDefinition = "TEXT", unique = true)
private String commentary;
#Column(name = "assessment",nullable = false,columnDefinition = "INT", unique = true)
private String assessment;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
#Entity(name = "statistic")
#Table(name = "statistic")
public class Statistic {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#Column(name = "time",nullable = false,columnDefinition = "TEXT", unique = true)
private String time;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
and
#Entity(name = "keep_routine")
#Table(name = "keep_routine")
public class KeepRoutine {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", updatable = false)
private Long id;
#ManyToOne
#JoinColumn(name = "id_routine_assignament")
private RoutineAssignament routineAssignament;
}
The entity relationship diagram is this:
My mistake is that it doesn't detect these relationships correctly.
When I run it it generates this:
Failed to initialize JPA EntityManagerFactory: mappedBy reference an unknown target entity property: com.example.demo.model.entities.KeepRoutine.routine_assignament in com.example.demo.model.entities.RoutineAssignament.keepRoutines
This error is reproduced with all three classes (KeepRoutine, Statistic and Score), I don't know why
Your OneToMany mapping is not appropriate. You need to use routineAssignament the property name instead of the table name routine_assignament as shown below. This property name is defined in the ManyToOne relationship.
#OneToMany(mappedBy = "routineAssignament")
private Set<Score> scores = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<Statistic> statistics = new HashSet<>();
#OneToMany(mappedBy = "routineAssignament")
private Set<KeepRoutine> keepRoutines = new HashSet<>();
I have two entities which is giving me error on creation of datasource
Entity1
#NoArgsConstructor
#Entity
#Table(name = "person_details")
public class PersonDetails {
#Id
private String pid;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "exist_flag")
private String existFlag;
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "pid", nullable = false)
private List<AddressDetails> addressDetails;
}
Entity 2 | EDIT 1
#Data
#NoArgsConstructor
#Entity
#Table(name = "address_details")
public class AddressDetails {
private String street;
#Column(name = "address_exist_flag")
private String addressExistFlag;
#ToString.Exclude
#EqualsAndHashCode.Exclude
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "pid", insertable = false, updatable = false)
private PersonDetails personDetails;
}
Getting error as below:
I am getting error as "No identifier specified for entity: AddressDetails".
How to resolve in such case? Can we use spring data jpa having OneToMany mapping in such case where one entity do not have primary key ?
The error you are getting is because you are using the same column name for 2 different columns.
#Id
private String pid;
and
#JoinColumn(name = "pid"
means that you want both your id column and your foreign key column to be named "pid", hence the error. I would suggest using a name like "addressDetailsFk" for the JoinColumn attribute.
I have tow entity User and Project that they have "one to many" relationship and I want to find the User then find the specific Project that belong to User and then update it, but I can't.
framework Struts2 + Hibernate .
#Entity (name = "User")
#Table (name = "users")
public class User implements Serializable{
#Id
#Column (name = "user_id", columnDefinition = "number")
#SequenceGenerator(name = "seq", sequenceName = "gen")
#GeneratedValue(strategy = GenerationType.AUTO, generator = "seq")
private int id;
#Basic
#Column(name = "user_name", columnDefinition = "nvarchar2(20)")
private String userName;
#Basic
#Column(name = "password", columnDefinition ="nvarchar2(20)")
private String password;
#Basic
#Column(name = "create_date",columnDefinition = "date")
private Date creation_date;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "user_id")
private List<Project> projectses;
public List<Project> getProjectses() {
return projectses;
}
public void setProjectses(List<Project> projectses) {
this.projectses = projectses;
}
and Project entity
#Entity(name = "Project")
#Table(name = "project")
public class Project implements Serializable {
#Id
#Column(name = "project_id" , columnDefinition = "number")
#SequenceGenerator(name = "projectSeq", sequenceName = "projectGen")
#GeneratedValue(strategy = GenerationType.AUTO,generator = "projectSeq")
private int projectId;
#Basic
#Column(name = "project_name" , columnDefinition = "nvarchar2(20)")
private String projectName;
#Basic
#Column(name = "project_description" , columnDefinition = nvarchar2(20)")
private String projectDescription;
#Basic
#Column(name = "start_date",columnDefinition = "date")
private Date startDate;
#Basic
#Column(name = "due_date",columnDefinition = "date")
private Date dueDate;
#Basic
#Column(name = "project_status",columnDefinition = "nvarchar2(20)")
private String projectStatus;
#Basic
#Column(name = "project_amount",columnDefinition = "number(8)")
private int projectAmount;
Three corrections come in mind, that may make your code behave well:
Use EntityManager#find() instead of HQL to lookup entity by id;
Use only one of #Basic or #Column (I'd prefer #Column), there is no need to use both for a single element;
If error is "value is too long for column", maybe it is time to check if some of Project elements are longer than 20 chars defined in columnDefinition?
Check length of string elements in Project entities, and if there are some longer than 20 characters, say, 500, modify columnDefinition for those elements, e. g.:
#Column(name = "project_description", columnDefinition = "nvarchar2(500)")
private String projectDescription;
I also suggest to drop tables after such modifications (to allow JPA create new according to new definitions) or manually modify their definitions in DB.
User u = (User)entityManager.createQuery(SELECT u FROM User u JOIN FETCH u.Project where u.id = :id).setParameter("id",your_userId).uniqueResult();
Get The user object , you will get it with the set of projects associated with that user
update the data you want : -
List<Project> userProjects = u.getProjectses();
for(int i = 0 ; i < userProjects.size() ; i++){
Project p = userProjects.get(i);
entityManager.getTransaction().begin();
p.setProjectName("test");
entityManager.merge(p);
entityManager.getTransaction().commit();
}
With JPA annoations, I want to reuse same embedded object like this :
#Entity
public class User {
#Embedded
public Address homeAddress;
#Embedded
public Address workAddress;
}
#Embeddable
public class Address {
public String code;
public String city;
...
}
I can specify SQL column names with #AttributeOverrides, #AttributeOverride and #Column, but it's verbos. Is it possible to specify just a prefix to add to each column for homeAddress and workAddress ?
Thanks,
Xavier
If you would like to use multiple same Embedded class. You have to do #AttributeOverrides for all columns.
Try as below;
Reference JPA AttributeOverrides
#Embeddable
public class Address {
private String state;
#Column(name = "zip_code")
private String zip;
}
#Entity(name = "Employee")
public class Employee implements Serializable {
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "state", column = #Column(name = "province_1")),
#AttributeOverride(name = "zip", column = #Column(name = "postal_code_2"))
})
private Address address_1;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "state", column = #Column(name = "province_2")),
#AttributeOverride(name = "zip", column = #Column(name = "postal_code_2"))
})
private Address address_2;
}
My suggestion, if there are one or more Embedded value in your Entity. Try to use #CollectionTable.
#CollectionTable(name = "EMPLOYEE_ADDRESS", joinColumns = #JoinColumn(name = "ADDRESS_ID"))
private List<Address> addressList;
Reference JPA CollectionTable
adding this works for me (i'm using hibernate as JPA provider though)
<property name="hibernate.implicit_naming_strategy" value="org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl" />
In 2022 (after 9 Years) #zaw-than-oo -s answer is still valid :-( .
This "Duplicate" answer is for reference if sombody wants to improve jpa-embedded.
Here is a working crossplatform example based on #zaw-than-oo -s answer
with verbose java-jpa and easy to use android-room
#androidx.room.Entity
#javax.persistence.Entity
#javax.persistence.Inheritance(strategy = javax.persistence.InheritanceType.SINGLE_TABLE)
public class AppHardware {
#javax.persistence.Id
#javax.persistence.GeneratedValue(strategy = javax.persistence.GenerationType.AUTO)
#androidx.room.PrimaryKey(autoGenerate = true)
private int id;
// max is embedded without column renaming
#androidx.room.Embedded
#javax.persistence.Embedded
private ProfileCommon max;
// min is embedded with column renaming
#androidx.room.Embedded(prefix = "min")
#javax.persistence.Embedded
#javax.persistence.AttributeOverrides({
// Verbose: every persisted property in ProfileCommon needs an entry
// see https://stackoverflow.com/questions/12912063/jpa-multiple-embedded-fields-with-prefix
#AttributeOverride(name = "added", column = #Column(name = "minadded")),
#AttributeOverride(name = "apkName", column = #Column(name = "minapkName")),
#AttributeOverride(name = "versionCode", column = #Column(name = "minversionCode")),
#AttributeOverride(name = "versionName", column = #Column(name = "minversionName")),
#AttributeOverride(name = "size", column = #Column(name = "minsize"))
})
private ProfileCommon min;
// getter and setter onmitted
}
#javax.persistence.MappedSuperclass
public class ProfileCommon {
private long added; // date
private String apkName;
private long versionCode;
private String versionName;
private long size;
// getter and setter onmitted
}