JPA: uni-directional OneToMany question - java

I have the following classes:
class A{
#OneToOne(cascade=CascadeType.ALL)
private B b;
}
class C{
#ManyToOne
private A a;
}
class B{
#OneToOne
private A a;
#MapKey(name = "name")
#OneToMany(cascade = CascadeType.ALL, ...)
#JoinColumn(...)
private Map<String C> cs;
}
How do I have to specify the mapping on B.cs to join where B.a == C.a?
Is this possible? Or do I have to change the property C.a to C.b? (I would prefer to keep it as it is, as the entity B is just a helper class.)
I also tried to change B to #Embeddable, but Map is not supported for embeddables.

JPA requires that all relationships be by Id (the foreign key references the primary key).
So, you need to either add a #ManyToOne from C to B.
Or, ensure that B's Id is the foreign key to A (add #Id on the #OneToOne from B to A and remove A's other #Id).
If B was a subclass of A instead of having a OneToOne this would also work.
If you are using EclipseLink, you can defined more complex criteria for a relationship. You would need to define the OneToMany's foreign keys using a DescriptorCustomizer and the OneToManyMapping API.

I think you can extends B from A.
If this doesn't work for you, maybe you can add a transient property to refer A's id,
#Transient
Integer getId1() {
return a.getId();
}
and join C using id1 instead of B's primary key.
Edit: This doesn't work.

Related

Lazy One-to-one Optional Bidirectional Mapping using Hibernate annotations

I want to create a Lazy One-to-one Bidirectional 'Optional' Mapping using Hibernate annotations. I know that the normal usage of #MappedBy and #JoinColumn result in N+1 queries being fired every time.
Is there a way I can avoid this? Not just at runtime, but at the POJO level. I am using Hibernate 4.3, so can't think about bytecode enhancement.
Further, if there is no way out, is it possible to apply criteria on unidirectional mappings. For example, I have A <-> B, and C -> A as mappings. And I am searching on B. Is it possible to apply a restriction on C when C is clearly unidirectional with A?
The #OneToOne annotaion doesn't work in hibernate as needed. Please consider the #LazyToOne or try using #OneToMany like #OneToOne. Also you can attempt #PrimaryKeyJoinColumn.
p.s. The #LazyToOne annotation doesn't exist in JPA realization, you should use #OneToOne(fetch = FetchType.LAZY, optional = false) there
I could not find a complete but minimal examples of LAZY bidirectional #OneToOne, so here it is. It is neither hibernate-version-dependent nor does it misuse #OneToMany.
Parent
Defines the id and is responsible for managing the consistency/synchronization, but technically does not own the relationship, because it can not reference any unique index in B (or at least we do not want to add redundant data).
#Entity
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#OneToOne(
mappedBy = "a",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private B b;
public void setB(B b) {
if (b == null) {
if (this.b != null) {
this.b.setA(null);
}
} else {
b.setA(this);
}
this.b = b;
}
// ... other setters/getters
}
Child
Technically owns the relationship by re-using the id of parent A.
#Entity
public class B {
#Id
// Not generated but shared with A
private Long id;
#OneToOne(fetch = FetchType.LAZY)
#MapsId
#JoinColumn(name = "id") // otherwise use "a_id" instead of "id" in the DB column
private A a;
// ... other setters/getters
}
And this is how the tables should look like (assuming postgres):
CREATE TABLE a (
id bigint NOT NULL PRIMARY KEY,
);
CREATE TABLE b (
id bigint NOT NULL PRIMARY KEY,
FOREIGN KEY (id) REFERENCES a(id);
);

Hibernate.initialize exception - Cutting dependency chain

I have a Class A which has an object of Class B which has an object of Class C. I want to get object of class B from object of class A without getting object of class C in b. (I have , and want to keep it this way, everything with lazy loading)
I am doing:
Hibernate.initialize(a.getObjectOfClassB());
But get exception. Is there any way to do what i want? Cutting the hibernate initialize chain?
Thanks in advanced!
So your entity structures appear to be mapped as follows:
public class EntityA {
#OneToMany(mappedBy = "a")
private List<EntityB> bList;
}
public class EntityB {
#ManyToOne
private EntityA a;
#OneToMany(mappedBy = "b")
private List<EntityC> cList;
}
public class EntityC {
#ManyToOne
private EntityB b;
}
So you have a specific EntityA that you want to fetch it's associated EntityB instances. You can obtain that list either at query time or as a post initialization step.
The important thing to note here is that the mappings between A - B - C are using #OneToMany which are lazily fetched by default.
To do this at query time:
SELECT a
FROM EntityA a
JOIN FETCH EntityB b
WHERE a.id = :entityAId
The returned EntityA already has your List<EntityB> already loaded for you and you need to do nothing else.
To do this as a post initialization step after you've fetched a single EntityA instance.
Hibernate.initialize(entityA.getBList());
or
entityA.getBList().size();

JPA foreign key - insert new record if necessary?

Is it possible to create some combination of annotations, that provide following:
Have 2 tables (one-2-many relationship)
Is it possible on JPA level without programming, just create object of "one" class and if there is id set that just make it reference in "many" table and in case that id is not set, create new record in "one" table and make reference to that id in "many" table
No. You will need to create all the objects by your self.
What you can do is to use cascade to do a automatic persist if you want to.
It would be something like:
a.setB(b);
b.getAList().add(a);
entityManager.persist(a);
And in your classes you would map like:
public class A {
// other methods and ID
#ManyToOne
#JoinColumn(name = "b_id")
private B b;
}
public class B {
// other methods and ID
#OneToMany(mappedBy = "b", cascade = CascadeType.PERSIST)
private List<A> aList;
}

Java EE, creating entity object with one to one association

I have two entitys, A and B. A has a one to one relationship of B.
class A {
String aValue;
B b;
}
class B {
String bValue;
}
The class B stuff are already pre populated. Now, a user on a website selects what B he wants to submit. On the server we get an Id of what B that was.
The Question:
How do I create a new A, without actually do a DB query asking for the B that has this id. I mean, the A table in database only has a id reference. One should be able to set that Id without fetching the B.
If you are using JPA and Assuming the following:
#Entity
#Table(name="A")
class A {
#Id
#Column(name="id")
private int id;
String aValue;
#OneToOne
B b;
// Getters, setters and other stuff
}
#Entity
#Table(name="B")
class B {
#Id
#Column(name="id")
private int id;
Integer Id;
String bValue;
// Getters, setters and other stuff
}
If you now the id of entity B. You can simply make persist as follows:
B b = new B();
b.setId(1000); //Assuming that you know the id.
//There is no necessary fill all the object. Just the PK is needed.
A a = new A();
a.setId(100);
a.setAValue("nothing");
a.setB(b);
em.persist(a);
I have tested this with Hibernate as Persistence Provider. If you are using other ORM please specify it.
You should take a look at JPA 2.0.
With JPA you can define a relationship between 2 entites to automatically retrieve the related entities.

Hibernate custom join clause on association

I would like to associate 2 entities using hibernate annotations with a custom join clause. The clause is on the usual FK/PK equality, but also where the FK is null. In SQL this would be something like:
join b on a.id = b.a_id or b.a_id is null
From what I have read I should use the #WhereJoinTable annotation on the owner entity, but I'm puzzled about how I specify this condition...especially the first part of it - referring to the joining entity's id.
Does anyone have an example?
Here's an example using the standard parent/child paradigm that I think should work using the basic #Where annotation.
public class A {
...
#ManyToOne(fetch = FetchType.EAGER) // EAGER forces outer join
#JoinColumn(name = "a_id")
#Where(clause = "a_id = id or a_id is null") // "id" is A's PK... modify as needed
public B getB() { return b; }
}
public class B {
...
#OneToMany(mappedBy = "b")
public List<A> getA() { return a; }
}

Categories