I create a base class for all entities to every new entity class extend it.
in base class I use annotation for orm, below code:
public class BaseEntity<I> implements IBaseEntity<I> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", nullable = false)
private I id;
public I getId() {
return id;
}
public void setId(I id) {
this.id = id;
}}
then I create a class as below:
#SuppressWarnings("serial")
#Entity
#Table(name = FoodEntity.TABLE_NAME, schema = "public")
public class FoodEntity extends BaseEntity<Long> {
public static final String TABLE_NAME = "T_Food";
#Column(name = "NAME", unique = true, nullable = false, length = 500)
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}}
but, when I execute a sample to test my classes, I get below exception:
Initial SessionFactory creation failed.org.hibernate.AnnotationException: No identifier specified for entity: FoodEntity
Exception in thread "main" java.lang.ExceptionInInitializerError
at ir.msr.projects.crawler.HibernateUtil.buildSessionFactory(HibernateUtil.java:31)
at ir.msr.projects.crawler.HibernateUtil.<clinit>(HibernateUtil.java:14)
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: FoodEntity
at org.hibernate.cfg.InheritanceState.determineDefaultAccessType(InheritanceState.java:266)
at org.hibernate.cfg.InheritanceState.getElementsToProcess(InheritanceState.java:211)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:731)
at org.hibernate.boot.model.source.internal.annotations.AnnotationMetadataSourceProcessorImpl.processEntityHierarchies(AnnotationMetadataSourceProcessorImpl.java:249)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess$1.processEntityHierarchies(MetadataBuildingProcess.java:222)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:265)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:691)
I found my answer, I have to use #MappedSuperclass for BaseEntity Class(Parent Class).
Try to create BaseEntity abstract and anotated Id put to your main class, or use annotation #MappedSuperclass
#MappedSuperclass
public class BaseEntity<I> implements IBaseEntity<I> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ID", nullable = false)
private I id;
public I getId() {
return id;
}
public void setId(I id) {
this.id = id;
}
}
or
public abstract class BaseEntity<ID extends Serializable, T extends BaseEntity<ID, T>> {
protected ID id;
public abstract ID getId();
public void setId(ID id) {
this.id = id;
}
}
Related
I am mapping Entities in Hibernate with JPA and Spring Data and when I run application I get
Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [id] on this ManagedType [p.s.t..entity.BaseEntity]
at org.hibernate.metamodel.internal.AbstractManagedType.checkNotNull(AbstractManagedType.java:128) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
at org.hibernate.metamodel.internal.AbstractManagedType.getAttribute(AbstractManagedType.java:113) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
at org.hibernate.metamodel.internal.AbstractManagedType.getAttribute(AbstractManagedType.java:111) ~[hibernate-core-5.3.12.Final.jar:5.3.12.Final]
at org.springframework.data.jpa.repository.query.QueryUtils.toExpressionRecursively(QueryUtils.java:633) ~[spring-data-jpa-2.1.11.RELEASE.jar:2.1.11.RELEASE]
at org.springframework.data.jpa.repository.query.JpaQueryCreator.complete(JpaQueryCreator.java:175) ~[spring-data-jpa-2.1.11.RELEASE.jar:2.1.11.RELEASE]
I have a superclass BaseEntity:
#MappedSuperclass
#Getter
#Setter
public abstract class BaseEntity implements Serializable {
#Id
#GeneratedValue
private Long Id;
private String uuid = UUID.randomUUID().toString();
#Override
public boolean equals(Object that) {
return this == that ||
that instanceof BaseEntity && Objects.equals(uuid, ((BaseEntity) that).uuid);
}
#Override
public int hashCode() {
return Objects.hash(uuid);
}
}
Regular class Task, which extends the BaseClass
#Getter
#Setter
#Table(name = "task")
#Entity
#NoArgsConstructor
#NamedEntityGraph(
name = "Task.detail",
attributeNodes = {
#NamedAttributeNode("attachments"),
#NamedAttributeNode("tags")
}
)
public class Task extends BaseEntity {
private String title;
private String description;
private LocalDateTime createdAt;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "task_id")
private Set<Attachment> attachments = new HashSet<>();
#ManyToMany
#JoinTable(
name = "tags_tasks",
joinColumns = #JoinColumn(name = "task_id"),
inverseJoinColumns = #JoinColumn(name = "tag_id")
)
private Set<Tag> tags = new HashSet<>();
public Task(String title, String description, LocalDateTime createdAt) {
this.title = title;
this.description = description;
this.createdAt = createdAt;
}
public void addAttachment(String filename, String comment) {
attachments.add(new Attachment(filename, comment));
}
public Set<Attachment> getAttachments() {
return attachments;
}
public void addTag(Tag tag) {
tags.add(tag);
}
public void removeTag(Tag tag) {
tags.remove(tag);
}
}
TaskView for JPA query projection:
public interface TaskView {
Long getId();
String getUuid();
String getTitle();
String getDescription();
LocalDateTime getCreatedAt();
}
And JpaRepository interface:
interface TasksCrudRepository extends JpaRepository<Task, Long> {
#EntityGraph(value = "Task.detail", type = EntityGraphType.LOAD)
List<Task> findAll();
List<TaskView> findAllProjectedBy();
}
The last method - findAllProjectedBy() - in the TaskCrudRepository causes the exception pasted at the begnining of this post.
When I remove getId() method from TaskView it starts, but then I am not able to display the id of the Task in the projection.
So the question is what I am missing in this whole classes structure?
I am using:
Spring Boot 2.1.9.RELEASE
Java 11
Hibernate Core 5.3.12.FINAL
JPA 2.2
There is a typo in BaseEntity when defining ID field. Should be camelcase id instead of Id.
#MappedSuperclass
#Getter
#Setter
public abstract class BaseEntity implements Serializable {
#Id
#GeneratedValue
private Long id;
private String uuid = UUID.randomUUID().toString();
#Override
public boolean equals(Object that) {
return this == that ||
that instanceof BaseEntity && Objects.equals(uuid, ((BaseEntity) that).uuid);
}
#Override
public int hashCode() {
return Objects.hash(uuid);
}
}
I create two classes with many to many relation between them, like as below:
#Entity
#Table(name = FoodEntity.TABLE_NAME)
public class FoodEntity extends BaseEntity<Long> {
public static final String TABLE_NAME = "T_FOOD";
#ManyToMany
#JoinTable(
name = "T_FOOD_FOODCATEGORY",
joinColumns = { #JoinColumn(name = "FOOD_ID") },
inverseJoinColumns = { #JoinColumn(name = "FOOD_CATEGORY_ID") })
private Set<FoodCategoryEntity> categories;
public Set<FoodCategoryEntity> getCategories() {
return categories;
}
public void setCategories(Set<FoodCategoryEntity> categories) {
this.categories = categories;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "FOOD_ID", nullable = false)
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
}
and :
#Entity
#Table(name = FoodCategoryEntity.TABLE_NAME)
public class FoodCategoryEntity extends BaseEntity<Long> {
public static final String TABLE_NAME = "T_FOOD_CATEGORY";
#ManyToMany(mappedBy = "categories")
private Set<FoodEntity> foods;
public Set<FoodEntity> getFoods() {
return foods;
}
public void setFoods(Set<FoodEntity> foods) {
this.foods = foods;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "FOOD_CATEGORY_ID", nullable = false)
#Override
public Long getId() {
return id;
}
#Override
public void setId(Long id) {
this.id = id;
}
}
but when I test this relation with junit,spring and hibernate, I get below exception:
Caused by: org.hibernate.MappingException: Could not determine type for: java.util.Set, at table: T_FOOD, for columns: [org.hibernate.mapping.Column(categories)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:455)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:422)
at org.hibernate.mapping.Property.isValid(Property.java:226)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:597)
at org.hibernate.mapping.RootClass.validate(RootClass.java:265)
at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:329)
at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:451)
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:889)
... 46 more
I checked annotation package references, and all ID column names, but all of them are correct.
point : I also use the HSQLDB database whose storage location it is a file.
I found my problem.
mapping class in persistence.xml was incorrect.
You annotations infer property access type mapping as #Id is placed on getter
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "FOOD_ID", nullable = false)
#Override
public Long getId() {
return id;
}
But collection annotaions are placed on field level
#ManyToMany
#JoinTable(
name = "T_FOOD_FOODCATEGORY",
joinColumns = { #JoinColumn(name = "FOOD_ID") },
inverseJoinColumns = { #JoinColumn(name = "FOOD_CATEGORY_ID") })
private Set<FoodCategoryEntity> categories;
While effective configuration is (not) specified on getter
public Set<FoodCategoryEntity> getCategories() {
return categories;
}
You should not mix two types of configurations.
I'm trying to insert a record with composite primary key, but at the time of saving a new record I get this message:
e = (org.springframework.orm.jpa.JpaSystemException)
org.springframework.orm.jpa.JpaSystemException: Could not set field
value [POST_INSERT_INDICATOR] value by reflection...
#Getter
#Setter
#Entity
#EqualsAndHashCode
#Table(name = "produto")
#IdClass(ProdutoId.class)
public class Produto implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_produto")
private Long idProduto;
#Id
#Column(name = "oficina", insertable = false, updatable = false)
private Long idOficina;
#ManyToOne
#JoinColumn(name = "oficina")
private Oficina oficina;
}
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode
#Data
public class ProdutoId implements Serializable {
public Long idProduto;
public Long idOficina;
}
#Repository
public interface ProdutoRepository extends JpaRepository<Produto, ProdutoId> {}
Has anyone ever seen a bug like this?
To create composite primary key you can refer this example,
#Entity
#Table(name="testuserrole")
public class UserRole{
#EmbeddedId
private UserRoleId id = new UserRoleId();
public UserRoleId getId() {
return id;
}
public void setId(UserRoleId id) {
this.id = id;
}
#Transient
public long getUserId() {
return id.userId;
}
public void setUserId(long userId) {
id.userId=userId;
}
#Transient
public long getRoleId() {
return id.roleId;
}
public void setRoleId(long roleId) {
id.roleId=roleId;
}
}
#Embeddable
class UserRoleId implements Serializable {
#Column(name = "user_id")
public long userId;
#Column(name = "role_id")
public long roleId;
}
I have the code
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractModel implements Serializable, Comparable<AbstractModel> {
private static final long serialVersionUID = -4479726024447228668L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
private Long id;
...
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class AbstractHistoricModel extends AbstractModel {
private static final long serialVersionUID = -3596885940998632065L;
#Column(name = "pblc_id")
...
#Entity
#SequenceGenerator(initialValue = 0, name = "idgen", sequenceName = "abstract_claim_type_seq")
#XmlAccessorType(XmlAccessType.FIELD)
public class AbstractClaimType extends AbstractHistoricModel {
private static final long serialVersionUID = -3840541568639732203L;
#Column(name = "nam")
private String name;
public AbstractClaimType() { super(); }
#Field
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
...
#Entity
#Table("retr_clm_mthd")
#SequenceGenerator….
#FieldModel
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#AttributeOverride(name="nam", column=#Column(name="retr_clm_mthd_nam", length=255))
public class Retrospective extends AbstractClaimType {
...
and when I create the database in memory to test
2013-04-11 14:15:28,445 ERROR (org.hibernate.tool.hbm2ddl.SchemaExport:org.hibernate.tool.hbm2ddl.SchemaExport.execute(SchemaExport.java:386)) - HHH000231: Schema export unsuccessful
org.hibernate.tool.hbm2ddl.ImportScriptException: Error during statement execution (file: '/import.sql')
Caused by: java.sql.SQLException: Column not found: RETR_CLM_MTHD_NAM in statement
I look the scriptdb and there is
CREATE MEMORY TABLE RETR_CLM_MTHD(….,NAM VARCHAR(255),….)
Why not retr_clm_mthd_nam?
What is wrong?
You don't have any attribute named "nam" in the superclass. You have one named "name":
private String name;
i would use a ModelBase with an ID and a Timestamp for every class/entity. But when i user the Long type for the Primary Key in the JPARepository<> interface i get the message
Not an entity: class java.lang.Long
Code:
#MappedSuperclass
public class ModelBase implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false, columnDefinition = "datetime")
private Date lastModified;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
#PreUpdate
#PrePersist
public void updateLastModified() {
lastModified = new Date();
}
}
Modelclass inheritanced from Modelbase
#Entity
#Table(name = "Name")
public class Name extends ModelBase implements Serializable {}
Repo
public interface NameRepository extends JpaRepository<Long, Name>{}
what am i doing wrong?
thanks
It's backwards:
JpaRepository<Name, Long>
First the entity, then the ID. Check JPARepository javadoc.