I'm getting the following error:
Could not determine type for: java.util.Set, at table: Ruleset, for columns: [org.hibernate.mapping.Column(ruleset)]
class snippet:
#Entity
public class Ruleset implements java.io.Serializable {
#Id
#OneToOne(targetEntity = RulesetStatus.class)
private Integer id;
private Set<Rule> ruleset = new HashSet<Rule>(0);
public Ruleset() {
}
public Ruleset(Integer ID, Set<Rule> ruleset) {
this.id = ID;
this.ruleset = ruleset;
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public Set<Rule> getRuleSet(){
return this.ruleset;
}
public void setRuleset(Set<Rule> ruleset) {
this.ruleset = ruleset;
}
}
I've figured out that annotating ruleset as Transient makes the problem go away, but then ruleset won't be persisted to the DB. How do I tell hibernate about the type of this field?
I'm very new to Hibernate so I'm totally lost here.
__________________________Edit__________________________
The actual relationship should have been #ManyToMany as a rule can be in many rulesets and a ruleset can have many rules.
I added the #ManyToMany annotation to the set, then did not have a corresponding set in the Rule Class to map to. I added the set in the rule class, added the #ManyToMany annotation to that, and no I have no errors.
Does this seem correct?
By default, all fields (or properties) are mapped in JPA. That's why you have to tell the JPA provider what your Set is supposed to map (one-to-many, many-to-many, #ElementCollection, etc.), or map it as #Transient to tell the provider that you don't want the property to be persisted.
Related
I have an TimelineEntity entity, that uses HoTimelineType enum with custom integer value. That custom integer value is stored in the database. Implemented via Using #PostLoad and #PrePersist Annotations
Sprint JPA Repository is used to save and get entities.
Here is the issue:
#Entity
#Table(name = TABLE_NAME)
#IdClass(TimelineKey.class)
public class TimelineEntity {
public interface Persistence {
String TABLE_NAME = "timelines";
}
#Id
#Column(name = "node_id")
private Long nodeId;
#Id
#Column(name = "timeline_id")
private Long timelineId;
#Column(name = "ho_timeline_type")
private Integer hoTimelineTypeValue;
#Transient
private HoTimelineType hoTimelineType;
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public Long getTimelineId() {
return timelineId;
}
public void setTimelineId(Long timelineId) {
this.timelineId = timelineId;
}
public HoTimelineType getHoTimelineType() {
return hoTimelineType;
}
public void setHoTimelineType(HoTimelineType hoTimelineType) {
this.hoTimelineType = hoTimelineType;
}
public Integer getHoTimelineTypeValue() {
return hoTimelineTypeValue;
}
public void setHoTimelineTypeValue(Integer hoTimelineTypeValue) {
this.hoTimelineTypeValue = hoTimelineTypeValue;
}
#PostLoad
private void postLoad() {
this.hoTimelineType = HoTimelineType.of(hoTimelineTypeValue);
}
#PrePersist
private void prePersist() {
this.hoTimelineTypeValue = hoTimelineType.getValue();
}
}
#Eager
public interface TimelineEntityRepository extends JpaRepository<TimelineEntity, TimelineKey> {
List<TimelineEntity> findByNodeId(Long nodeId);
}
#Autowired
private TimelineEntityRepository timelineEntityRepository;
...
TimelineEntity newTE = new TimelineEntity();
newTE.setNodeId(10L);
newTE.setTimelineId(22L);
newTE.setHoTimelineType(HoTimelineType.TYPE_1);
newTE = timelineEntityRepository.save(newTE);
When the newTE entity is saved, prePersist is invoked, and inside this method, the hoTimelineType is null and I get NPE. nodeId and timelineId are not nulls. If I stay with a debugger on the last line, outside of prePersist, I see that hoTimelineType has the value, I set before.
When I load entities, inserted with test data, everything works fine and both hoTimelineType and hoTimelineTypeValue have not nullable values.
I skipped the code of TimelineKey and HoTimelineType to simplify the example. Can add it, if needed.
What could reset hoTimelineType? What do I miss?
It seems there is no way to control the saving behaviour of spring jpa repository proxy.
Possible solutions for issue:
Via javax.persistence.Converter. It is pretty clear, the structe of an entity is simple. Can confirm it works fine with Spring Jpa Repository generation.
Explicitely set hoTimelineTypeValue before you save an entity. Error-prone solution. Everytime you save an entity you must think about the difference between the hoTimelineTypeValue and hoTimelineType.
You could enrich setters and getters of the entity class, to explicitely control the consistency between the fields. It makes implementation of entity classes not so obvious. You get more compicated solution for nothing. As a result error-prone solution. Do not recommend it as well.
Cause of disadvantages of #2 and #3 I do not provide examples. It makes no sense.
Example of the solution #1 can be found here: Using JPA 2.1 #Converter Annotation
Hi I have a confusing error with my Spring-boot-JPA-Hibernate classes.
I used the JPA Dali tools to create the Entity classes from my SQL Schema.
While using them (with Spring-boot-jpa / hibarnate) I have some strange problems with unmatched queries.
Here is one example:
Properties:
hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.hibernate.ddl-auto=none
spring.datasource.url=jdbc:mysql://localhost:3306/users
spring.datasource.username=root
spring.datasource.password=root
Entity:
#Entity
#Table(name="n_user")
#NamedQuery(name="NUser.findAll", query="SELECT n FROM NUser n")
public class NUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int id;
private String imageUrl1;
private String name_first;
public NCaterer() {
}
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getImageUrl1() {
return this.imageUrl1;
}
public void setImageUrl1(String imageUrl1) {
this.imageUrl1 = imageUrl1;
}
public String getName_first() {
return this.name_first;
}
public void setName_first(String name_first) {
this.name_first = name_first;
}
}
Repository:
public interface UserRepo extends CrudRepository<NUser, Long> {
}
But Hibernate creates this query of it:
Hibernate:
/* select
generatedAlias0
from
NUser as generatedAlias0 */ select
nuser0_.id as id1_0_,
nuser0_.image_url1 as image_ur2_0_,
nuser0_.name_first as name_firs3_0_
from
n_user nuser0_
The Problem here is the image_url1 it should be imageurl1 as described in the Entity class. This happens on several points.
Why do Hibernate transform CamelCase getters into camel_case in the query? And how can I config it not to do it?
If you want to specify column name by your own use #Column annotation for your fields.
Example:
#Column(name = "imageUrl1")
private String imageUrl1;
#Column(name = "nameFirst")
private String name_first;
It seems there have been many people experiencing the same problem in different circumstances. Maybe go and have a look at the different naming strategies below:
Naming Strategy One
Naming Strategy Two
Naming Strategy Three
You can however change the configuration of your hibernation. Have a look here for further help with regards to that. Or, go and have a look at this post and see how someone changed it using the above methods.
I'm building one application using JPA, I want to have a parent entity called "BaseEntity" with the attribute ID and then the rest of the entities extending this entity and then having their own attributes. The field id in the parent class is protected. However when I start the server I'm getting the following error:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: com.fgonzalez.domainmodel.User
Of course if I place the id field in the class User, it is working fine but this is not what I want. The weird thing is if I use xml files for the hibernate mappings instead of JPA, it works fine, but not with JPA. Any idea where can be the problem? Attached the code:
Base Entity:
public class BaseEntity implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
#Column(name="id")
protected Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
And User entity:
#Entity
#Table(name="users")
public class User extends BaseEntity{
/**
*
*/
private static final long serialVersionUID = 1L;
/**
*
*/
#Column(name="EMAIL",nullable=false,length=50,insertable=true,updatable=true)
private String email;
#Column(name="PASSWORD",nullable=false,length=50,insertable=true,updatable=true)
private String password;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email=email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
Thank you in advance!!
You can't do that this way: BaseEntity isn't an #Entity, so #Id shouldn't even be processed.
If Hibernate does process it while using xml, that's probably a non-portable specificity.
You could implement some entity hierarchy, but I wouldn't do it in this case. You can only extend once, and this doesn't look like a real hierarchy: only one root, shared by every class?
You can find more information on entity inheritance here: http://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html
You could use compositions instead of inheritance. In this case, just annotate your User class (which wouldn't be an #Entity) with #Embeddable, and have a field annotated with #EmbeddedId on the using class.
Still, I wouldn't do that: it seems more DRY, but it has no more benefits that replacing String everywhere with something else just to not repeat yourself (which you would then do anyway).
I would just have an #Id Long id; field in every entity, freeing them from hierarchy hell. It looks more boilerplate, but will be much easier in the long term, with no obvious disadvantage.
If you are going implement inheritance in JPA, you are not suppose to do like in java. JPA got its own implementation strategies. Have a look here and choose the one that best suits your need
I'm using hibernate JPA (without Spring) and it's working well, but I have come across a problem which has stumped me for the last 3 days.
I have written some generic DAO classes and am using them to persist my objects. They all work fine, except for one class of object which is not being persisted. No exceptions are thrown. I've tried debugging inside the hibernate code and found that the reason the entity is not being persisted is that in the org.hibernate.event.def.DefaultFlushListener onFlush() method, source.getPersistenceContext().getEntityEntries().size() == 0 so no flushing is performed. But I can't work out why that would be the case.
The classes in question look like this:
#Entity
#Table(name="er_batch_runs")
public class BatchRun implements Serializable, Comparable<BatchRun>, BatchBean {
private Long runId;
private String hostname;
.... more field here
#Override
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="runseq")
#SequenceGenerator(name="runseq", sequenceName="er_batch_runs_seq", allocationSize=1 /*, initialValue = 10*/)
#Column(name="batch_run_id")
public Long getId() {
return runId;
}
public void setId(long runId) {
this.runId = runId;
}
#Column(name="hostname")
public String getHostname() {
return hostname;
}
public void setHostname(String hostname) {
this.hostname = hostname;
}
pretty straightforward hibernate JPA stuff.
Here's another class:
#Entity
#Table(name="er_batch_txns")
public class BatchTxn implements Serializable, Comparable<BatchTxn>, BatchBean {
private long id;
.......... more fields
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="batchtxnseq")
#SequenceGenerator(name="batchtxnseq", sequenceName="ER_BATCH_TXNS_SEQ", allocationSize=1/*00, initialValue = 10*/)
#Override
#Id
#Column(name="BATCH_TXN_ID")
public Long getId() {
return id;
}
the BatchBean interface is what allows me to use generic DAOs like this:
public Long create(BatchBean newInstance) {
getOpenEntityManager().persist(newInstance);
logger.debug("hopefully created {} with id {}",newInstance.getTypeName(),newInstance.getId());
return newInstance.getId();
}
Transactions are being handled manually. I've set the flush type to COMMIT (ie flush on commit) and when I've completed the persist, I do a commit. After the persist, then BatchTxn object has been assigned a primary key from the sequence. When I debug hibernate I can see that getPersistenceContext().getEntityEntries() returns an empty Map.
so the question is why the BatchTxn is not being persisted by the commit, when the BatchRuns, and 5 other classes which implement BatchBean, are?
I'm using hibernate 3.6.0 Final
The only thing I saw that is suspected in your code is this in the BatchTxn class:
private long id;
This will be set automatically to zero. Maybe you should use Long (with a capital letter)?
I have the following annotated Hibernate entity classes:
#Entity
public class Cat {
#Column(name = "ID") #GeneratedValue(strategy = GenerationType.AUTO) #Id
private Long id;
#OneToMany(mappedBy = "cat", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Set<Kitten> kittens = new HashSet<Kitten>();
public void setId(Long id) { this.id = id; }
public Long getId() { return id; }
public void setKittens(Set<Kitten> kittens) { this.kittens = kittens; }
public Set<Kitten> getKittens() { return kittens; }
}
#Entity
public class Kitten {
#Column(name = "ID") #GeneratedValue(strategy = GenerationType.AUTO) #Id
private Long id;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private Cat cat;
public void setId(Long id) { this.id = id; }
public Long getId() { return id; }
public void setCat(Cat cat) { this.cat = cat; }
public Cat getCat() { return cat; }
}
My intention here is a bidirectional one-to-many/many-to-one relationship between Cat and Kitten, with Kitten being the "owning side".
What I want to happen is when I create a new Cat, followed by a new Kitten referencing the Cat, the Set of kittens on my Cat should contain the new Kitten. However, this does not happen in the following test:
#Test
public void testAssociations()
{
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction tx = session.beginTransaction();
Cat cat = new Cat();
session.save(cat);
Kitten kitten = new Kitten();
kitten.setCat(cat);
session.save(kitten);
tx.commit();
assertNotNull(kitten.getCat());
assertEquals(cat.getId(), kitten.getCat().getId());
assertTrue(cat.getKittens().size() == 1); // <-- ASSERTION FAILS
assertEquals(kitten, new ArrayList<Kitten>(cat.getKittens()).get(0));
}
Even after re-querying the Cat, the Set is still empty:
// added before tx.commit() and assertions
cat = (Cat)session.get(Cat.class, cat.getId());
Am I expecting too much from Hibernate here? Or is the burden on me to manage the Collection myself? The (Annotations) documentation doesn't make any indication that I need to create convenience addTo*/removeFrom* methods on my parent object.
Can someone please enlighten me on what my expectations should be from Hibernate with this relationship? Or if nothing else, point me to the correct Hibernate documentation that tells me what I should be expecting to happen here.
What do I need to do to make the parent Collection automatically contain the child Entity?
It won't automatically add it. You have to add it yourself.
I wouldn't directly call Kitten.setCat() either. The typical pattern for this is to put a method in Cat like:
public void addKitten(Kitten kitten) {
if (kittens == null) {
kittens = new HashSet<Kitten>();
}
kittens.add(kitten);
kitten.setCat(this);
}
and then simply call:
cat.addKitten(kitten);
When working with bi-directional associations, you have to handle both sides of the "link" and it is very common to use defensive link management methods for that, as suggested by #cletus. From Hibernate Core documentation:
1.2.6. Working bi-directional links
First, keep in mind that Hibernate
does not affect normal Java semantics.
How did we create a link between a
Person and an Event in the
unidirectional example? You add an
instance of Event to the collection of
event references, of an instance of
Person. If you want to make this link
bi-directional, you have to do the
same on the other side by adding a
Person reference to the collection in
an Event. This process of "setting
the link on both sides" is absolutely
necessary with bi-directional links.
Many developers program defensively
and create link management methods to
correctly set both sides (for example,
in Person):
protected Set getEvents() {
return events;
}
protected void setEvents(Set events) {
this.events = events;
}
public void addToEvent(Event event) {
this.getEvents().add(event);
event.getParticipants().add(this);
}
public void removeFromEvent(Event event) {
this.getEvents().remove(event);
event.getParticipants().remove(this);
}
The get and set methods for the
collection are now protected. This
allows classes in the same package and
subclasses to still access the
methods, but prevents everybody else
from altering the collections
directly. Repeat the steps for the
collection on the other side.
More References
1.2.6. Working bi-directional links (this one is the more obvious)
6.3.2. Bidirectional associations
Chapter 21, Example: Parent/Child
Java Persistence with Hibernate