I'm getting this Hibernate error:
org.hibernate.MappingException: Could not determine type for:
a.b.c.Results$BusinessDate, for columns: [org.hibernate.mapping.Column(businessDate)]
The class is below. Does anyone know why I'm getting this error??
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"businessDate"
})
#XmlRootElement(name = "Results")
#Entity(name = "Results")
#Table(name = "RESULT")
#Inheritance(strategy = InheritanceType.JOINED)
#Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Results implements Equals, HashCode
{
#XmlElement(name = "BusinessDate", required = true)
protected Results.BusinessDate businessDate;
public Results.BusinessDate getBusinessDate() {
return businessDate;
}
public void setBusinessDate(Results.BusinessDate value) {
this.businessDate = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"raw",
"display"
})
#Entity(name = "Results$BusinessDate")
#Table(name = "BUSINESSDATE")
#Inheritance(strategy = InheritanceType.JOINED)
public static class BusinessDate implements Equals, HashCode
{
....
Update: This code was generated by HyperJaxB. So I don't claim to understand it all, just trying to make some changes to it!
Update2: Here's the full (yah it's big) src file
Using a static nested class as a field type is fine and supported. But Hibernate won't know how to map such a complex type to a column type (which is what the error message says).
So you'll need either to create a user type to handle this or to annotate the Results.BusinessDate field with a #OneToOne annotation to persist it in another table (I would also remove the #Inheritance which is useless but this is not the problem here).
Update: Just to clarify, using a user type or mapping the complex type with #OneToOne does work. The following code works perfectly (tested):
#Entity
public class EntityWithStaticNestedClass implements Serializable {
#Id
#GeneratedValue
private Long id;
#OneToOne
private EntityWithStaticNestedClass.StaticNestedClass nested;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public EntityWithStaticNestedClass.StaticNestedClass getNested() {
return nested;
}
public void setNested(EntityWithStaticNestedClass.StaticNestedClass nested) {
this.nested = nested;
}
#Entity
public static class StaticNestedClass implements Serializable {
#Id
#GeneratedValue
private Long id;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
}
}
And both entities get well persisted in their respective tables. But you're not showing the entire code nor the exact error so I can't say why it didn't for you (maybe you're missing #Id etc).
That being said, if you don't want businessDate to be persisted at all, annotate it with #Transient (with JPA, fields are persistent by default):
Update: You can't mix field and property access. So you need to annotate getBusinessDate() with #Transienthere. Sorry, I couldn't guess that from the shown code and I thought it would be obvious.
Same comment as Kevin Crowell. You might also look at not using inner classes for entity types. I've actually never seen someone do that with Hibernate, so I'm not sure if it's even possible, or how you would map it.
The #Inheritance annotation on the BusinessDate inner class seems a little fishy too - the inner class is static, and does not inherit from another entity, unless Hibernate treats inner classes as "inherited."
Overall, not really sure what you're trying to accomplish, but you might be making your life harder than it should be. I would recommend not using inner classes, and just mapping all the entities in a more simple/straightforward fashion.
Related
I have a Hibernate Entity, BaseEvent, which works fine:
import javax.persistence.*;
#Entity
#Table(name = "base_event")
#SequenceGenerator(name = "seq", allocationSize = 1, sequenceName = "seq")
public class BaseEvent
{
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "seq")
#Column(name = "id")
protected Long id = null;
#Column(name = "my_field", nullable = false)
protected String myField;
public Long getId()
{
return id;
}
public void setId(final Long id)
{
this.id = id;
}
public String getMyField()
{
return myField;
}
public void setMyField(final String myField)
{
this.myField = myField;
}
}
I want to identify when this object is changed and update some Map in my application. The easiest way I could think of doing this was to extend BaseEvent and override the setter:
import java.text.MessageFormat;
public class ExtendedEvent extends BaseEvent
{
#Override
public void setMyField(final String myField)
{
System.out.println(MessageFormat.format("Setting myField to {0}", myField));
super.setMyField(myField);
}
}
This works fine in my application, but then when I come to persist the Entity, Hibernate complains it doesn't know what an ExtendedEvent is.
java.lang.IllegalArgumentException: Unknown entity: my.package.ExtendedEvent
I can see that extending Hibernate Entities is a non-trivial problem, especially when you start adding fields - but all I want is for Hibernate to treat ExtendedEvent as a BaseEvent (because it is). Is there a simple solution for this?
Make base event #MappedSuperclass and extending class #Entity
so
#MappedSuperclass
public class BaseEvent
and
#Entity
#Table(whatever)
public class ExtendedEvent extends BaseEvent
If you want to update your map only when changes are updated in the data store, I would recommend implementing onFlushDirty in a Hibernate Interceptor. This method gets called whenever the Session is flushed to the database for every entity change. You can check the object type in the onFlushDirty method for your entity of interest and property of interest.
Hi I have a two tables like below .
1) Task - id,name
2) Resource - id,name,defaultTask(foreign key to Task.id)
The mapping is one to Many - one task can have many resource.
The code for Task is like below.
#Entity
public class Task implements Serializable {
private long m_id;
private String m_name;
#Id
#GeneratedValue(
strategy = GenerationType.AUTO
)
public long getId() {
return this.m_id;
}
public void setId(long id) {
this.m_id = id;
}
public String getName() {
return this.m_name;
}
public void setName(String name) {
this.m_name = name;
}
#OneToMany
#JoinColumn(
name = "defaultTask"
)
private List<Resource> m_relatedResources;
public List<Resource> getrelatedResources() {
return m_relatedResources;
}
public void setrelatedResources(List<Resource> relatedResources) {
m_relatedResources = relatedResources;
}
And the code for Resource class is like below.
#Entity
public class Resource implements Serializable {
private Long m_id;
private String m_name;
#Id
#GeneratedValue(
strategy = GenerationType.AUTO
)
public Long getId() {
return this.m_id;
}
public void setId(Long id) {
this.m_id = id;
}
public String getName() {
return this.m_name;
}
public void setName(String name) {
this.m_name = name;
}
Task m_task;
#ManyToOne
#JoinColumn(
name = "defaultTask"
)
public Task getTask() {
return this.m_task;
}
public void setTask(Task task) {
this.m_task = task;
}
}
When i execute it I am getting an error like
Initial SessionFactory creation failed.org.hibernate.MappingException: Could not determine type for: java.util.List, for columns: [org.hibernate.mapping.Column(relatedResources)]
What have i done wrong ?How can i fix the problem ?
You can't apply annotations to methods or fields randomly. Normally, you should apply your annotations the same way as #Id..
In Task class OneToMany should be like
#OneToMany
#JoinColumn(
name = "defaultTask"
)
public List<Resource> getrelatedResources() {
return m_relatedResources;
}
Field access strategy (determined by #Id annotation). Put any JPA related annotation right above each method instead of field / property as for your id it is above method and it will get you away form exception.
Also there appears to be an issue with your bidrectional mapping metntioned by #PredragMaric so you need to use MappedBy which signals hibernate that the key for the relationship is on the other side. Click for a really good question on Mapped by.
Many mistakes here:
you're annotating fields sometimes, and getters sometimes. Half of the annotation will be ignored: you must be consistent. It's one or the other.
You're not respecting the Java Bean naming conventions. The getter must be getRelatedResources(), not getrelatedResources().
A bidirectional association must have an owner side and an inverse side. In a OneToMany, the One is always the inverse side. The mapping should thus be:
.
#ManyToOne
#JoinColumn(name = "defaultTask")
public Task getTask() {
return this.m_task;
}
and
#OneToMany(mappedBy = "task")
public List<Resource> getRelatedResources() {
return m_relatedResources;
}
I also strongly advise you to respect the Java naming conventions. Variables should be named id and name, not m_id and m_name. This is especially important if you choose to annotate fields.
You're mixing annotating fields and getters in the same entity, you should move your #OneToMany to a getter
#OneToMany
#JoinColumn(mappedBy = "task")
public List<Resource> getrelatedResources() {
return m_relatedResources;
}
and yes, as the others mentioned, it should be mappedBy = "task". I'll upvote this teamwork :)
#JoinColumn is only used on owner's side of the relation, ToOne side, which is Resource#task in your case. On the other side you should use mappedBy attribute to specify bidirectional relation. Change your Task#relatedResources mapping to this
#OneToMany(mappedBy = "task")
private List<Resource> m_relatedResources;
Also, as #Viraj Nalawade noticed (and others, obviously), mapping annotations should be on fields or properties, whatever is used for #Id takes precedence. Either move #Id to field, or move #OneToMany to getter.
I have some trouble with Hibernate 4 and inheritance:
I use a ChildData class which inherit from BaseData by a JOIN inheritance strategy. My mapping is done by annotation in classes.
Everything is working fine except that when I delete a ChildData instance (with session.delete() or with a Hql query) the BaseData entry is also deleted.
I understand that in most case this is the awaited behavior, but for my particular case, I would like to preserve the BaseData entry no matter what for history purpose.
In other words I want all actions on the child class to be cascaded to base class except deletion.
I have already tried #OnCascade on the child class, with no success.
Is it a way to achieve this by code or do I have to use a SQL Trigger ON DELETE ?
EDIT :
Base Class
#Entity
#Table(name = "dbBenchHistory", uniqueConstraints = #UniqueConstraint(columnNames = "Name"))
#Inheritance(strategy = InheritanceType.JOINED )
public class DbBenchHistory implements java.io.Serializable {
private int id;
private String name;
private String computer;
private String eap;
private Date lastConnexion;
private Set<DbPlugin> dbPlugins = new HashSet<DbPlugin>(0);
private Set<DbSequenceResult> dbSequenceResults = new HashSet<DbSequenceResult>(
0);
public DbBenchHistory() {
}
public DbBenchHistory(int id, String name) {
this.id = id;
this.name = name;
}
public DbBenchHistory(int id, String name, String computer, String eap,
Date lastConnexion, Set<DbPlugin> dbPlugins,
Set<DbSequenceResult> dbSequenceResults) {
this.id = id;
this.name = name;
this.computer = computer;
this.eap = eap;
this.lastConnexion = lastConnexion;
this.dbPlugins = dbPlugins;
this.dbSequenceResults = dbSequenceResults;
}
#Id
#Column(name = "Id", unique = true, nullable = false)
#GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
//Getters/Setters
Child Class :
#Entity
#Table(name = "dbBench")
#OnDelete(action=OnDeleteAction.NO_ACTION)
public class DbBench extends DbBenchHistory {
private Set<DbProgram> dbPrograms = new HashSet<DbProgram>(0);
private Set<DbUser> dbUsers = new HashSet<DbUser>(0);
public DbBench() {
}
public DbBench(Set<DbProgram> dbPrograms,
Set<DbUser> dbUsers) {
this.dbPrograms = dbPrograms;
this.dbUsers = dbUsers;
}
//Getters/Setters
But I'm starting to think that I was wrong from the beginning and that inheritance was not the good way to handle this. If nothing shows up I will just go for BenchHistory - Bench being a simple one-to-one relationship
EDIT2 :
I edit while I can't answer my own question for insuficient reputation
I feel completly stupid now that I found the solution, that was so simple :
As I said, I was using hibernate managed methods : session.delete() or hql query. Hibernate was doing what he was supposed to do by deletintg the parent class, like it would have been in object inheritance.
So I just bypass hibernate by doing the deletion of the child class with one of the simplest SqlQuery on earth. And the base class entry remain untouched.
I understand that I somehow violate the object inheritance laws, but in my case it is really handy.
Thanks to everyone for your time, and believ me when I say I'm sorry.
I don't think Hibernate/JPA supports this. What you basically want is conversion from a subclass to a superclass, and not a cascading delete. When you have an object of the subclass, the members from the superclass are treated no different than the members of the subclass.
This can be solved through writing some logic for it though:
public void deleteKeepSuperclassObject(final ChildData childData) {
final BaseData baseDataToKeep = new BaseData();
//populate baseDataToKeep with data from the childData to remove
em.persist(baseDataToKeep);
em.remove(childData);
}
My simplified model looks like this:
#Entity public class Aspect extends Model {
#Id public Long id;
#OneToMany(cascade = CascadeType.ALL) public List<Restriction> restrictions;
}
#Entity public class Restriction extends Model {
#Id public Integer id;
#ManyToOne public RestrictionTemplate restrictionTemplate;
}
#Entity public class RestrictionTemplate extends Model {
#Id private Integer id;
}
Basically the idea is this: each Aspect has a set of Restrictions. And each Restriction itself relies on a RestrictionTemplate.
I want Aspect creation form to like this: user can select some RestrictionTemplates and on form submit new Restrictions should be created and associated with new Aspect.
Let me explain once again: On form submission I want to create Aspect and relating Restrictions based on RestrictionTemplate's ids provided.
Whicn names should the fields in the form have in order to make such binding possible?
The naming which works for direct relantionships:
restrictions[0].restrictionTemplate.id
restrictions[1].restrictionTemplate.id
doesn't work here (creates Aspect entry in DB, but no Restriction entries).
I think you simply must write a bit of code for that, in which you search for the RestrictionTemplates corresponding to the passed IDs and then assigning them to the new instance of Aspect:
List<RestrictionTemplates> templates = new ArrayList<RestrictionTemplates>();
for (int crtTplId : passedIds) {
templates.add(entityManager.find(RestrictionTemplates.class, crtTplId));
}
List<Restriction> restrictions = new ArrayList<Restriction>();
for (RestrictionTemplates crtTpl : templates) {
restrictions.add(new Restriction(crtTpl));
}
Aspect aspect = new Aspect();
aspect.restrictions = restrictions;
entityManager.persist(aspect);
PS: as I understand, there can be Restrictions that do not belong to an Aspect. If that is not true, than you should make your Aspect-Restriction relationship bilateral, Restriction being the owning side:
#Entity public class Aspect extends Model {
#Id public Long id;
#OneToMany(cascade = CascadeType.ALL, mappedBy="aspect") public List<Restriction> restrictions;
}
#Entity public class Restriction extends Model {
#Id public Integer id;
#OneToMany(/*+ add the #JoinColumn for marking the column not nullable*/) public Aspect aspect;
#ManyToOne public RestrictionTemplate restrictionTemplate;
}
Important: please note that I'm talking about Play! framework version 1 (1.2.6), not 2.x
I have 2 entities in my Play! v1 application, like that:
#Entity
#Table(name = "T_FOO")
public class Foo extends GenericModel {
#Id
#Column(name = "NAME")
public String name;
public static List<Foo> paginate(int start, int count) {
return all().from(start).fetch(count);
}
}
and
#Entity
#Table(name = "T_BAR")
public class Bar extends GenericModel {
#Id
#Column(name = "NAME")
public String name;
public static List<Bar> paginate(int start, int count) {
return all().from(start).fetch(count);
}
}
In my controller, I can do that without problem:
public static void index() {
List<Foo> foo = Foo.paginate(1, 5);
List<Bar> bar = Bar.paginate(2, 5);
render(foo, bar);
}
As you can see, these 2 entities are quite similar, so I created a super class to regroup common methods:
#MappedSuperclass
public class MyGenericModel<T> extends GenericModel {
public static <T> List<T> paginate(int start, int count) {
return all().from(start).fetch(count);
}
}
and make it as the parent of my entities, for example:
#Entity
#Table(name = "T_FOO")
public class Foo extends MyGenericModel<Foo> {
#Id
#Column(name = "NAME")
public String name;
}
However, with this modification, I get the following error when I try to call Foo.paginate() method:
UnsupportedOperationException occured : Please annotate your JPA model with #javax.persistence.Entity annotation.
play.exceptions.JavaExecutionException: Please annotate your JPA model with #javax.persistence.Entity annotation.
at play.mvc.ActionInvoker.invoke(ActionInvoker.java:237)
at Invocation.HTTP Request(Play!)
Caused by: java.lang.UnsupportedOperationException: Please annotate your JPA model with #javax.persistence.Entity annotation.
It seems that Play! wants me to annotate MyGenericModel with #Entity annotation, which I don't want.
I thought that annotating MyGenericModel with #MappedSuperclass would help me to avoid this problem, but it is not the case.
What did I make wrong, and how to make it work correctly?
Thanks.
Unfortunately you can't call the function all() from your class MyGenericModel because that function is enhanced at runtime and only for classes annotated with #Entity.
Possible solution could be that you use your own entity manager for your queries.
Or you could go back to your first option, there was nothing wrong with that :)
Unfortunately (this is also my pain) Generics are not yet supported by Ebean:
https://groups.google.com/forum/#!searchin/ebean/generics/ebean/QWjpI0LRCiA/io-Lm_gfYE4J