I am trying to adapt my data model to use a BaseEntity base-class. The following code represents the general idea:
#MappedSuperclass
public abstract class BaseEntity implements HasAuditInfo {
#Id
#GeneratedValue
private Long id;
#Column(unique = true, nullable = false)
private String uuid;
private Long createdById;
#Temporal(value = TemporalType.TIMESTAMP)
#Column(nullable = false)
private Date createdOn;
private Long changedById;
#Temporal(value = TemporalType.TIMESTAMP)
#Column(nullable = false)
private Date changedOn;
#Column(nullable = false)
private Long changedOnValue;
private Boolean active;
private Long deactivatedById;
#Temporal(value = TemporalType.TIMESTAMP)
private Date deactivatedOn;
#NotNull
#DecimalMin("0")
private Integer version = 0;
private Long domainId;
[... Getters/Setters etc ...]
}
The following is an example of a derived entity:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Address extends BaseEntity implements Serializable, Comparable<Address> {
private static final long serialVersionUID = 6301090657382674578L;
// Address Fields
#NotBlank(message = "Address Line 1 is a mandatory field.")
private String addressLine1;
private String addressLine2;
private String country;
#NotBlank(message = "Region is a mandatory field.")
private String region;
#NotBlank(message = "City is a mandatory field.")
private String city;
#NotBlank(message = "Zipcode is a mandatory field.")
private String zipcode;
[... Getters/Setters etc ...]
}
If I'm understanding the JPA documentation correctly, this should be perfectly valid, yet I get the following error from EclipseLink when deploying my code:
Entity class [class
com.x.y.z.Address] has no primary key specified.
It should define either an #Id, #EmbeddedId or an #IdClass. If you
have defined PK using any of these annotations then make sure that you
do not have mixed access-type (both fields and properties annotated)
in your entity class hierarchy.
I've tried a few things to work around this:
Upgrading to EclipseLink 2.3 (I'm currently using 2.2)
Making BaseEntity non-abstract
Moving the #Id annotation and field directly into Address
Annotating the getId() method instead of field both in BaseEntity and in Address.
None of these approaches have had any effect, short of migrating my code to Hibernate (or some other, better, JPA implementation), is there anything I can do?
The solution is to explicitly name each column in BaseEntity, as follows:
#MappedSuperclass
public abstract class BaseEntity {
#Id
#GeneratedValue
#Column(name = "id")
#SearchableId
protected Long id;
#Column(name = "uuid", unique = true, nullable = false)
protected String uuid;
#Column(name = "createdById")
protected Long createdById;
#Temporal(value = TemporalType.TIMESTAMP)
#Column(name = "createdOn", nullable = false)
protected Date createdOn;
#Column(name = "changedById")
protected Long changedById;
#Temporal(value = TemporalType.TIMESTAMP)
#Column(name = "changedOn", nullable = false)
protected Date changedOn;
#Column(name = "changedOnValue", nullable = false)
protected Long changedOnValue;
#Column(name = "active")
protected Boolean active;
#Column(name = "deactivatedById")
protected Long deactivatedById;
#Temporal(value = TemporalType.TIMESTAMP)
#Column(name = "deactivatedOn")
protected Date deactivatedOn;
#Version
#Column(name = "version")
protected Integer version = 0;
#Column(name = "domainId")
protected Long domainId;
You should not get this error. And definitely not if you move the #Id into the Address.
Are you sure you recompiled/deployed your code after making the changes?
If you remove the TABLE_PER_CLASS inheritance does it work? (does Address have subclasses?)
Related
i am tryning to join two entities where typDossAmo can have a list of DossMedic
but i get the following error:
Entity class [class ma.cnss.wstest.TypDossAmo] must use a #JoinColumn instead of #Column to map its relationship attribute [drugs].
public class TypDossAmo implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "ID")
private BigInteger id;
#Id
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 9)
#Column(name = "NUM_DOSS")
private String numDoss;
#Column(name = "p_tab_medic")
#OneToMany(mappedBy="doss")
private List<DossMedic> drugs;........
public class DossMedic implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected DossMedicPK dossMedicPK;
#Column(name = "ID")
private BigInteger id;
#Column(name = "NOMBRE")
private BigInteger nombre;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="NUM_DOSS")
private TypDossAmo doss;
The idea of the annotation #Column is for common columns without any relationship with other tables, when you use #JoinColumn is to say to the ORM that two tables have a relationship and the way to join them is with this column.
In this case the solution is change the annotation #Column by #JoinColumn in TypDossAmo
public class TypDossAmo {
#JoinColumn(name = "p_tab_medic")
#OneToMany(mappedBy="doss")
private List<DossMedic> drugs;
}
Entity fetched using Hibernate has all fields set to NULL. How can I avoid this?
This is my Jpa Repository.
#Repository
public interface PolicyRepository extends JpaRepository<Entity, Long>{
Entity findByEntSeqNo(#Param("entSeqNo") long entSeqNo);
}
When debugged I can see that fetched data are inside a field name $$_hibernate_interceptor
This is my entity class
#Entity
#Table(name = "ENTITY_TABLE")
#Lazy(value = false)
public class Entity extends AuditModel {
#Id
#Column(name = "ENT_SEQ_NO")
#GeneratedValue(generator="entitySeq")
#SequenceGenerator(name="entitySeq",sequenceName="\"ENT_SEQ_NO_seq\"", allocationSize=1)
private long entSeqNo;
#Column(name = "ENT_CUSTOMER_CODE")
#NotEmpty(message = "Customer Code is Required.")
private String entCustomerCode;
#Column(name = "ENT_CLAS_CODE")
#NotEmpty(message = "Class Code is Required.")
private String polcClasCode;
#Column(name = "ENT_PROD_CODE")
#NotEmpty(message = "Product Code is Required.")
private String entProdCode;
#Column(name = "ENT_BRANCH_CODE")
#NotEmpty(message = "Branch Code is Required.")
private String entBranchCode;
#Column(name = "ENT_YYY_NO")
#NotEmpty(message = "Yyy Number is Required.")
private String entYyylNo;
#Column(name = "ENT_XX_NO")
private String entXxNo;
#Column(name = "ENT_XXX_NO")
private String entXxxNo;
#Column(name = "ENT_COMMENCEMENT_DATE")
#Temporal(TemporalType.TIMESTAMP)
private Date entCommencementDate;
#Version
#NotNull(message = "Version is Required.")
#Column(name = "VERSION")
private int version;
#Column(name = "ENT_EXPIRY_DATE")
#NotNull(message = "Entity Expiry Date is Required.")
#Temporal(TemporalType.TIMESTAMP)
private Date entExpiryDate;
#Column(name = "ENT_DELIVERY_MODE")
private String entDeliveryMode;
#Column(name = "ENT_COLLECTED_BY")
private String entCollectedBy;
#Column(name = "ENT_COLLECTED_USER_NIC")
private String entCollectedUserNic;
#Column(name = "ENT_COLLECTED_USER_MOBILE")
private String entCollectedUserMobile;
#Column(name = "ENT_COLLECTED_DATE")
#Temporal(TemporalType.TIMESTAMP)
private Date entCollectedDate;
#Column(name = "ENT_POSTED_DATE")
#Temporal(TemporalType.TIMESTAMP)
private Date entPostedDate;
#Column(name = "ENT_POSTED_REF_NO")
private String entPostedRefNo;
#Column(name = "ENT_LANG_CODE")
private String entLangCode;
#Column(name = "ENT_PP1_ID", insertable = false, updatable = false)
private Long entPp1Id;
#Column(name = "ENT_STATUS")
private Short entStatus;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ENT_PP1_ID", referencedColumnName = "ID")
private Pp1 entPp1;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ENT_EPP1_ID", referencedColumnName = "ID")
private Epp1 entEpp1;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "xxx")
private Collection<TaskLog> taskLogColletion;
}
I'm asking this here since I couldn't find the exact cause for this behavior. All the Jpa operations are working fine and this happens only when I try to pick the details from the database. I also tried getOne method and the same problem occurs.
You do not need the method : Entity findByEntSeqNo(#Param("entSeqNo") long entSeqNo); in your jpa interface because entSeqNo is an id of your entity.
So whene you want to get one Entity by id you can just call policyRepository.getOne(the value of entSeqNo) provided by JpaRepository
Or you can use policyRepository.findById(the value of entSeqNo) provided by CrudRepository whitch is basically a superinterface of JpaRepository
Ps: Do no overwrite these methods in you interface.
I just cannot get the relationship working between my two classes mapped to SQL tables with Hibernate.
The Role class:
#Entity
#Table(name = "role")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#Column(name="name")
private String name;
#OneToMany(mappedBy="memberinfo")
private Set<Memberinfo> members;
...
}
And the Memberinfo class:
#Entity
#Table(name = "memberinfo")
public class Memberinfo {
#Id #GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id", nullable = false)
private int id;
#Column(name = "userid", nullable = false)
private String userid;
#Column(name = "email", nullable = false)
private String email;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "salt", nullable = false)
private String salt;
#Column(name = "name", nullable = false)
private String name;
#Column(name = "address")
private String address;
#Column(name = "phonenum")
private String phonenum;
#ManyToOne(targetEntity=Role.class)
#JoinColumn(name="role_id")
private Role role;
...
}
When i try to fetch data from the DB, it connects, but throws an exception:
"HTTP Status 500 - #OneToOne or #ManyToOne on model.Memberinfo.role references an unknown entity: model.Role".
If i delete the variable "Role", then it works, and i can fetch the membership data, but i need the connection between the two tables, but in this case, the previously mentioned exception appears every time.
No other solutions on stackoverflow worked for me so far.
Any idea what am i doing wrong?
The "unknown entity error" can be thrown if the class is not actually an Entity (not annotated whith javax.persistence #Entity) or if the persitence provider doesn't "know" the class (package not scanned).
Is the Role class imported in Memberinfo the correct one ? Maybe you are importing another Role class from another library.
I'm trying to implement an internationalization class to translate contents from database.
I have these tables:
And I have theses classes:
ProductModel:
public class ProductModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idproduct_model")
private Integer idproductModel;
#Size(max = 80, message = "El campo nombre esta vacio")
#Column(name = "name")
private String name;
#Size(max = 45, message = "El campo referencia esta vacio")
#Column(name = "productSuppReference")
private String productSuppReference;
...
Language:
public class LanguageCountry implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "id_language")
private Integer idLanguage;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 45)
#Column(name = "description")
private String description;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "languageCountry1")
private List<ProductModelI18n> productModelI18nList;
...
ProductModelI18n:
public class ProductModelI18n implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected ProductModelI18nPK productModelI18nPK;
#Size(max = 80)
#Column(name = "name")
private String name;
#Lob
#Size(max = 2147483647)
#Column(name = "description")
private String description;
#Size(max = 800)
#Column(name = "description2")
private String description2;
#JoinColumn(name = "language_country", referencedColumnName = "id_language", insertable = false, updatable = false)
#ManyToOne(optional = false)
private LanguageCountry languageCountry1;
ProductModelI18nPK:
#Embeddable
public class ProductModelI18nPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "product_model")
private int productModel;
#Basic(optional = false)
#NotNull
#Column(name = "language_country")
private int languageCountry;
I have problems because I need a double PK in a ProductModelI18n table to get a manytomany relation between productmodel and languageCountry and now I don't know how to do a join table in productModel.
I need an ArrayList/Map in ProductModel class.
Thank you in advance!
Jose
EDIT:
Sorry my bad I missed the fact that you have extra columns in the Join table, so just need to decompose the ManyToMany association between ProductModel and LanguageCountry into two OneToMany associations.
Your code should look like:
in ProductModel class:
#OneToMany
private List<ProductModelI18n> ProductLanguages;
In LanguageCountry class:
#OneToMany
private List<ProductModelI18n> ProductLanguages;
And in your ProductModelI18n class:
Keep all the other fields including the IdPK and add the following declarations.
#ManyToOne
#PrimaryKeyJoinColumn(name="productModel", referencedColumnName="idproductModel")
private ProductModel productModels ;
#ManyToOne
#PrimaryKeyJoinColumn(name="languageCountry", referencedColumnName="idLanguage")
private LanguageCountry LanguageCountries;
Note:
Make sure you include all the getters and setters.
There's no need to create the class ProductModelI18n to make a ManyToMany relation between productmodel and languageCountry.
You only need two Collections in these two classes mapped with #ManyToMany annotation where in one of the two sides you define a #JoinTable here's the code you need:
In ProductModel class:
#ManyToMany
#JoinTable(
name="ProductModelI18n",
joinColumns={#JoinColumn(name="productModel", referencedColumnName="idproductModel")},
inverseJoinColumns={#JoinColumn(name="languageCountry", referencedColumnName="idLanguage")})
private List<LanguageCountry> languageCountries;
And in your LanguageCountry class:
#ManyToMany(mappedBy="languageCountries")
private List<ProductModel> productModels;
And you will get a Join table between the two tables as represented in the picture.
For further information you can take a look at:
JPA 2 Tutorial – Relationships – Many To Many.
Java Persistence/ManyToMany
I had tables like Customer, Request and so on and each had ID field;
I have now an abstract
#MappedSuperclass instead that have
#Id
#GeneratedValue
private Long id
field, and all tables extends it with
#AttributeOverride(name="id", column=#Column(name="ID_CUSTOMER"). but now, when I'm trying to add customer to a table, I'm getting exception: Column ID_Customer cannot accept Null value.
when each table had it's own id fields, all works fine.
what's wrong?
Thanks
#MappedSuperclass
public abstract class GeneralEntity implements Serializable,Cloneable{
#Id
#GeneratedValue
#Column(name = "ID")
private Long id;
#Column(name = "CREATED",nullable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date created;
#Column(name = "MODIFIED")
#Temporal(TemporalType.TIMESTAMP)
private Date modified;
//getters,setters
#Entity
#Table(name = "CUSTOMER")
#AttributeOverrides({
#AttributeOverride(name = "id", column = #Column(name="ID_CUSTOMER")),
#AttributeOverride(name="created", column=#Column(name="CUSTOMER_REGISTERED",nullable = false))
})
public class Customer extends GeneralEntity{
// #Column(name = "ID_CUSTOMER")
// #Id
// #GeneratedValue
// private Long id;
#Column(name = "CUSTOMER_EMAIL", nullable = false, length = 25, unique = true, updatable = true)
private String email;
#Column(name="CUSTOMER_PASSWORD", nullable = false)
private String password;
//getters setters