How can I cast from one class to another class in hibernate - java

Suppose there are three classes:
One is:
#Entity
#Indexed
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
#Table(name = "tbl_a")
public class A {
#Id
#DocumentId
#GeneratedValue(generator="rwSpecSeq")
#SequenceGenerator(name="rwSpecSeq", sequenceName="RW_SPEC_SEQ")
private int id;
private String sampleAttribute;
//Getters and Setters
}
#Entity
#DiscriminatorValue("b")
public class B extends A {
}
#Entity
#DiscriminatorValue("c")
public class C extends A {
}
If one object is saved as B's object then if again I want to cast or change the object to C then it is giving class cast exception. Please tell me how to cast class in hibernate when merging.
My approach was something like this:
//Assuming that the object is C class' object.
A a = adminService.getA(request.getParameter("id"));
//before merging I did this
B b = (B)a;
adminService.save(b);

You just can't. Hibernate keeps the objects type when they are persisted to the database. And Java prevents casting objects from one type to another when they are incompatible.
In your case, you can't cast an instance of C in B. It would be like casting a String into an Integer.
Your best shot is to write a method that takes an instance of C and copies all the attributes of C into a new object of type B.

What does the adminService.getA(request.getParameter("id")); actually do? If it does something like:
hibernateSession.get(A.class,id);
then Hibernate will fetch the corresponing values from the row with that id, and create an instance of the class A you passed as argument (that's why you pass it there, from the javadocs: "Return the persistent instance of the given entity class with the given identifier"). This means that even if you've declared your Hibernate inheritance such that Entity C extends Entity B extends Entity A, and the corresponing classes extend eachothers in the same way, Hibernate will actually create an instance of A (not an instance of B or C which you adress as A), so that instance of A cannot be cast to B.
If however the id there corresponds to a row which is of type B (let's say), then if you do
A a = hibernateSession.get(B.class,id);
then you can do
B b = (B)a;
because your "a" objet is infact of type B (even though you initially treat it as A). However in this situation it would be simpler to just do:
B b = hibernateSession.get(B.class,id);
Again, the above will work if you actually saved an entity of type B (or C) in the row with that id (i.e. your discriminator colum contains the value for type B or C)

Related

How to fetch object using the List Association in Hibernate

I have a class A with setters and getters
class A{
private int id;
private List<B> b;
}
I want to fetch the A object based on the B objects. So suppose I have a list of B objects I want to get the A objects that contain the B.
So i decided to use in
Here is the code
Criteria criteria = session.createCriteria(A.class).setCacheable(false);
criteria.add(Restrictions.in("b",{list of B})).list();
This gives an error java.sql.SQLException: No value specified for parameter 1
How can I get object A using B
You should join the B's first:
Criteria criteria = session.createCriteria(A.class)
.setCacheable(false)
.setFetchMode("bList", FetchMode.JOIN)
.createAlias("bList", "b");
and then use an IN for the ids of b:
criteria.add(Restrictions.in("b.id",{list of B})).list();
Set your fetch mode accordingly whether you want the list of B's also apart from A.

JPA 3 level inheritance

First of all I've been all the morning seeking for a solution for my problem. I've found similar problems but no one fixed my problem :(
I have a 3 level inheritance on my Java classes model:
A <-- B <-- C
Mapping this into a Relational Data Base I've made
A (1) -- (0..1) B (1) -- (0..1) C, so my annotated Java classes are something like:
#Entity
#Inheritance(strategy=InheritanceType.JOINED)
#DiscriminatorColumn(name="type", discriminatorType=DiscriminatorType.INTEGER)
#XmlRootElement
public class A implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long idA;
private Integer type;
...
}
#Entity
#DiscriminatorValue("2")
#PrimaryKeyJoinColumn(name="idB", referencedColumnName="idA")
#XmlRootElement
public class B extends class A implements Serializable{
private Long idB;
private Integer type;
#OneToOne(cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
#JoinColumn(name = "idB")
private A a;
...
}
#Entity
#DiscriminatorValue("8")
#PrimaryKeyJoinColumn(name="idC", referencedColumnName="idB")
#XmlRootElement
public class C extends class B implements Serializable{
private Long idC;
#OneToOne(cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
#JoinColumn(name = "idC")
private B b;
...
}
I don't know why, invoking a Query SELECT c FROM C c retrieves me 0 result when I have info on that table. If I do the query SELECT b FROM B b it works fine. It seems to be something wrong with the hierarchy annotations I've used.
Any idea? Thank you in advance :)
Joined table inheritance means that when you have a C entity, there must be a row in the A, B AND C tables. If you have data in C but no corresponding data in A or B that match up, then you will get no C entities back - the data is invisible to JPA because it first queries the A table to see if there are rows with a Type=3, and then joins it to B and C.
So check that your java inheritance model actually matches the data model. You also show that B and C have a reference to their parent - this cause the same id field to be mapped twice, as it is in both the Entity's PrimaryKeyJoinColumn and the mapping's JoinColumn. Since the referenced A (or B) is apart of the B (or C), there is no need to also have an object referenence to it - any of the inherited get methods will return the data from the A table anyway.

Does #Inheritance default to SINGLE_TABLE, or does it default to "fallthrough" OR SINGLE_TABLE?

Consider the following scenario:
(The following things have been omitted: Constructors, Getters and Setters, #Column annotations, #Basic annotations, #Table annotations, imports and package declarations. The rest is EXACTLY as I intend it to be (even empty annotations))
#Inheritance(strategy=InheritanceType.JOINED)
#Entity
public class A {
#Id #GeneratedValue
private long id;
private String aValue;//There are getters and setters for this, but I omitted them
}
#Entity
public class B extends A {
private String bValue;
}
//Missing #Inheritance here - JPA2 says "default" #Inheritance if it is missing
//But what does that mean?
#Entity
public class C extends A {
private String cValue;
}
#Entity
public class D extends C {
private String dValue;
}
//Missing strategy, whose default, according to the annotation interface, is SINGLE_TABLE
#Inheritance
#Entity
public class E extends C {
private String eValue;
}
#Entity
public class F extends E {
private String fValue;
}
#Entity
public class G extends E {
private String gValue;
}
Quick summary of the classes without the syntax:
A (#Inheritance(strategy=InheritanceType.JOINED)
B, C (no annotation)
D, E (#Inheritance)
F, G
If you were to follow JPA's spec, should there be
A: tables for A, B, C, D, E, F and G, all containing id + classValue
B: tables for A, B, C, D and {EFG}, with A, B, C & D containing id + classValue, and {EFG} containing id + eValue + fValue + gValue + DTYPE
C: tables for A, B and {CDEFG}, with A and B containing id + classValue, and {CDEFG} containing id + cValue + dValue + eValue + fValue + gValue + DTYPE
Or is it some other scenario I haven't thought of yet?
I would test it, but I'm not sure whether it would be the implementation of JPA or the specification itself filling in the blanks of "What happens when an #Inheritance annotation is not missing, but has an undefined strategy"?
Personally I'm pretty sure C won't happen, but I don't know whether it will map like A or B.
Hence the question title:
Does #Inheritance default to "SINGLE_TABLE" (no matter whether it's missing or undefined), or does it default to "fallthrough" (check how the entity hierarchy above deals with things) and if that's not possible, "SINGLE_TABLE"? And what if the annotation is there, but doesn't have a strategy defined?
I think the correct answer is "It depends on your Implementation". From the JSR spec (JSR317 ยง2.12 "Inheritance Mapping Strategies"):
Support for the combination of inheritance strategies within a single entity inheritance hierarchy is not required by this specification.
In this case, the root of your hierarchy is A, with JOINED explicitly specified so then you'd have tables for each entity.
Now if your JPA implementation supported multiple inheritance types per hierarchy, judging from the Javadoc and Source of the annotation, I would personally expect there to be tables for A, B, C, D, {EFG}
As you point out, if the annotation is present, the strategy is SINGLE_TABLE unless explicitly specified. As the Javadoc and the Spec refer to the treatment of #Inheritance in terms of class hierarchies, I would think that if the current class does not have the annotation, I look to the parent and up the tree until I either find an annotation, or I reach the root of the class hierarchy (and default to SINGLE_TABLE)
For me it is not 100% clear, does following in JPA 2.0 specification
Support for the combination of inheritance strategies within a single entity
inheritance hierarchy is not required by this specification.
mean that:
if implemented, should honor all other constraints presented (most
likely) or
if implemented, can relax other constraints presented.
Luckily reference implementation has chosen first option. With EclipseLink #Inheritance without argument defaults to single table and not having #Inheritance annotation at all honours #Inheritance annotation found from the superclass (does not have to be immediate superclass). These entities will be mapped to five tables:
A: id dtype avalue
B: id bvalue
C: id cvalue
D: id dvalue)
E: id evalue, fvalue, gvalue
(B-E id being FK to A id)
Persisting entities works as expected, each entity is saved to tables of superclasses as well without problems.
you need to add inheritanse annotation with discriminator parameter to see all info about this stuff just visit [a link]http://www.java2s.com/Code/Java/JPA/SetDiscriminatorValue.htm

How to implement this simple association in jpa/hibernate

I have 2 test classes:
Class A{
B b;
// some other properties
}
Class B{
// some properties
}
every instance of A has only one instance of class B, but an instance of class B can be assigned to more than one instance of class A
like :
B b = new B();
A a1 = new A();
a1.setB(b);
A a2 = new A();
a2.setB(b);
what type of association is this?
At first I was thinking about a one-to-one unidirectional but maybe is a many-to-one? but I don't have any collection of A objects on B.
Can someone explain me what is the correct way to implements this association (using annotation)?
every instance of A has only one instance of class B, but an instance
of class B can be assigned to more than one instance of class A
So , A to B is the many-to-one relationship . B to A is the one-to-many relationship.
The following shows the bi-directional mapping between A and B using annotation:
#Entity
#Table(name="tableA")
Class A{
#ManyToOne
#JoinColumn(name = "B_ID")
B b;
// some other properties
}
#Entity
#Table(name="tableB")
Class B{
#OneToMany(mappedBy = "b")
List Set<A> listOfA= new ArrayList<A>();
// some other properties
}
Important points:
#Entity marks the java class as an hibernate entity. It is mapped to the name of the table specified in the #Table
If no #Table is specified ,by default , it is mapped to the table with the name that is equal to the unqualified class name of the entity.
#ManyToOne defines Class A to Class B 's relationship is many-to-one
In the relational database , one-to-many relationship is expressed by using the following foreign key constraint :
"Many side table" has a FK column which only accepts the PK of the "one side table".
This name of this FK column can be defined explictly by the name attribute of #JoinColumn. If #JoinColumn is not specified , then default value(s) with be used for this FK column , which concatenates with the name of "one side table", _ (underscore), and the name of the PK in the "one side table".
#OneToMany defines Class B to Class A 's relationship is one-to-many.
The relationship is:
B (One) ---to--> A (Many)

Unmapped POJO used as class type in a native query's result exception

Given a class:
class MyClass {
private String a;
private String b;
private String c;
}
and code like so:
Query q = getEntityManager()
.createNativeQuery('select a, b from table', MyClass.class);
It throws an exception. My solution is to add
'' as c
in the sql. However, the c in MyClass is a variable that I intend to put some calculated value into, and that c does not have any real mapping to the table, so the solution just puts the c with a blank value...
My question is, are there any alternatives?
You need to mark c as #Transient so that it is not mapped.

Categories

Resources