Mapping recursive relation via secondary table with Spring Data - java

I have database such as this:
CREATE TABLE unit
(
id INTEGER NOT NULL,
name VARCHAR,
);
CREATE TABLE unit_composition
(
parent_id INTEGER NOT NULL,
child_id INTEGER NOT NULL,
quantity INTEGER,
CONSTRAINT child_fk FOREIGN KEY (parent_id)
REFERENCES public.refdse (id) MATCH SIMPLE,
CONSTRAINT parent_fk FOREIGN KEY (parent_id)
REFERENCES public.refdse (id) MATCH SIMPLE
);
ALTER TABLE unit_composition
ADD CONSTRAINT composit_pk PRIMARY KEY (parent_id, art_nr);
I have a table of manufactory units. Each unit can have multiple sub-units, and sub-units can have multiple sub-sub-units and so on. Also I have a quantity field that shows how many sub-units are needed to manufactor a single unit. So it is kind of a tree relation.
Now I want to map it to classes with Spring Data. I have a Unit class with an Id and Name:
#Entity
#Table(name = "unit")
class Unit {
#Id
#Column(name = "id")
private int id;
#Column(name = "name")
private String name;
...
}
I've created a secondary class Part:
class Part {
private Unit unit;
private int quantity;
...
}
And I need unit class to have a field like List subUnits.
I tried to do it with a #SecondaryTable and #JoinColumn annotations, but I got an error saying "Relation unit_unit does not exist".
Also I tried to make Part an #Entity but it has no Id field.
Alternatively I tried to make #Embeddable class PartId and insert an instance into Part class like this:
#Embeddable
public class PartId implements Serializable {
private Unit parentUnit;
private Unit unit;
I'm getting an error in PartId class saying that "Basic type should not be Persistence Entity" because it's Embeddable and don't have a table assign to it.
So how can I make this work being able to get recursivly all sub-units (with sub-sub-units and so on) of a given Unit? I don't quite get it how can I map an entity that is really just links from table to itself.

So my first solution was to make Jdbc template repository and simply build necessary lists manually via SQL-queries. But I found much better and simplier solution that required adding an id column to unit_composition table and therefore making Part class an #Entity with #ManyToOne relationship to a Unit class. And the rest was simply done by Spring Data.

Related

Hibernate twice embedded entities

I have Hibernate 5.2.10 version and hibernate-jpa-2.1-api with version 1.0.0.Final. I am using MairaDB as database. In persistance.xml, set the property hibernate.ejb.naming_strategy as DefaultComponentSafeNamingStrategy but still I receive the same error:
Repeated column in mapping for entity. I do not want to use #attributeoverrides hibernate and I tried different methodes but still the same error. I want two or more embedded enities.
Thanks
You can't use DefaultComponentSafeNamingStrategy with Hibernate 5, because of it is an implementation of the old NamingStrategy interface from Hibernate 4.
As you probably know, Hibernate 5 uses two new interfaces ImplicitNamingStrategy and PhysicalNamingStrategy.
You can use this implicit naming strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl.
You will need to set hibernate.implicit_naming_strategy property (not hibernate.ejb.naming_strategy).
For these entities
#Embeddable
public class AuthorInfo {
#Column
private String authorInfo;
#OneToOne
private Book bestBook;
}
#Entity
public class Book {
#Id
private Long pid;
#Embedded
private AuthorInfo firstAuthor;
#Embedded
private AuthorInfo secondAuthor;
}
it creates this schema
create table Book (
pid bigint not null,
firstAuthor_authorInfo varchar(255),
secondAuthor_authorInfo varchar(255),
firstAuthor_bestBook_pid bigint,
secondAuthor_bestBook_pid bigint,
primary key (pid)
)
Unit test to check a schema: TwoEmbeddedStrategyTest.java

Define an inherited column to be part of composite primary key in JPA

We have an abstract base entity class that defines columns found in all of our entities (e.g. creation and modifications timestamps and related user IDs). For most of our entities, there are two related database tables: one that holds the "live" data, i.e. the current state of the entity; and one that holds the audit trail, i.e. all historical versions of the entity, as snapshots.
One of the columns shared by all entities (and defined in the base entity class) is a version number column, which is a simple running sequence that tells how many edits have been made to that particular entity. The version column is present in both the audit table and the "regular" table, but in the audit table, the version column is also part of a composite primary key, which is formed by combining the primary key of the "regular" entity and the version number. Simplified example (some entity-level annotations omitted for brevity):
#MappedSuperclass
public abstract class BaseEntity {
#Column(name = "version")
private Long version;
// Timestamps, user IDs etc.
}
#MappedSuperclass
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class PersonBase extends BaseEntity {
// All basic columns of a person defined here
}
public class Person extends PersonBase {
#Id
#Column(name = "id")
private long id;
// All references to other entities defined here
}
public class PersonAudit extends PersonBase {
#Id
#Column(name = "id")
private long id;
// FIXME: Version column should be part of composite primary key
// All foreign key columns defined here (can't have
// a direct FK relationship in an audit table, as you
// don't know which version to link to)
}
Is it possible to make the inherited version column be part of a composite primary key in the audit entities? I tried declaring the version column also in the PersonAudit table and adding the #Id annotation to it, but after that the version field in BaseEntity wasn't populated anymore. It'd be very convenient to have the field in BaseEntity as we use it in some generic Criteria Queries using the JPA static metamodel, and if we move the field declaration to the individual audit entities, we can't reference the column anymore in those queries.
P.S. We're using Hibernate, so Hibernate-specific solutions are also acceptable if JPA doesn't enable this.

JPA 2: how to declare primary-key columns in #ElementCollection tables

in JPA2 when we are using Embed-able (Basic Type like String.. etc ) object in Entity using with #ElementCollection and #CollectionTable annotation , the new table is created , but in new table how to declare primary-key contraint in column ? following is my code
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
private String salary;
#Transient
private String phnNum;
#Enumerated(EnumType.STRING)
private EmployeeType type;
#ElementCollection
#CollectionTable(name="vacations" , joinColumns=#JoinColumn(name="Emp_Id"))
private Collection<Vacation> vacationBooking;
#ElementCollection
private Set<String> nickNames;
...................
with this code the "vacation" and "employee_nickname" two tables are created in schema. but i want to declare the one primary-key column in both table . what i do for this?
It looks like a primary key per se is not supported by JPA 2.0:
From Wikibooks:
The JPA 2.0 specification does not provide a way to define the Id in the Embeddable. However, to delete or update an element of the ElementCollection mapping, some unique key is normally required. Otherwise, on every update the JPA provider would need to delete everything from the CollectionTable for the Entity, and then insert the values back. So, the JPA provider will most likely assume that the combination of all of the fields in the Embeddable are unique, in combination with the foreign key (JoinColumn(s)). This however could be inefficient, or just not feasible if the Embeddable is big, or complex.
Some JPA providers may allow the Id to be specified in the Embeddable, to resolve this issue. Note in this case the Id only needs to be unique for the collection, not the table, as the foreign key is included. Some may also allow the unique option on the CollectionTable to be used for this. Otherwise, if your Embeddable is complex, you may consider making it an Entity and use a OneToMany instead.
Do you mean that you want to assign 'id' from Employee table as foreign key to the Vacation table?
In that case, you should use #OneToMany instead of #ElementCollection

Joining a legacy table with no PK with Hibernate

I have 2 legacy tables:
CREATE TABLE A (
ID NUMBER PRIMARY KEY ,
DATA NUMBER
)
CREATE TABLE A_CONF (
A_ID NUMBER, // FK to A
INFO VARCHAR2(256)
)
Creating the JPA entity for A is straightforward. Yet, what can I do retrieve the multiple INFO fields that can be associated to an instance of A since there is no PK in A_CONF and therefore cannot create an entity for it?
Thanks for helping.
Seems like you are looking for what JPA calls an "element collection":
#Entity
public class A {
#Id
private Long id;
private Long data;
#ElementCollection
#CollectionTable(name="A_CONF", joinColumns=#JoinColumn(name="A_ID")) // A_ID would be the default join column
#Column(name="INFO")
private Set<String> infos; // using Set assuming unique values
}
You can define a primary key in your model class even if your table doesn't have one, just pick one or some columns in your model and put them as ids.

How to add a separate Primary Key to a Join Table in Hibernate

I have a question about Hibernate ManyToMany mappings. I have two classes A and B and the mapping between them is a ManyToMany mapping resolved by Hibernate:
#Entity
#Table(name="A")
public class A {
#Id
#GeneratedValue
private Long id;
#ManyToMany
#JoinTable(name="C", joinColumns=#JoinColumn(name="a_id"), inverseJoinColumns=#JoinColumn(name="b_id"))
private Set bs;
}
#Entity
#Table(name="B")
public class B {
#Id
#GeneratedValue
private Long id;
#ManyToMany(mappedBy="bs")
private Set bs;
}
As you can see, the Join Table I use is C. The foreign keys to A and B are "a_id" and "b_id". My understanding is, that Hibernate creates a composed Primary Key with a_id and b_id for table C.
I don't want to have an entity C in my model. But instead of a composed primary key on table C, I would like to have a generated ID and a unique constraint on the fields a_id and b_id.
Is it possible to tell Hibernate to use a separate primary key? Without adding an entity C?
I would appreciate any help.
Thanks a lot!
You should do iyt like this. But it can be appled only for list (not for sets)
#Entity
#TableGenerator(name="ids_generator", table="IDS")
public class Passport {
...
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(name="PASSPORT_VISASTAMP")
#CollectionId(
columns = #Column(name="COLLECTION_ID"),
type=#Type(type="long"),
generator = "ids_generator"
)
private Collection<Stamp> visaStamp = new ArrayList();
...
}
I don't think it is possible. And I don't see a problem in defining a C entity.
If you have any additional information ind the join-table, it will not be accessible to you, because your Set contains the target entity - A or B.
Also, your Sets would better make use of generics - i.e. Set<A> and Set<B>.
Btw, Hibernate might not be alarmed by the fact that the table creates another entity - using your current mapping might work (disregarding completely the id column). When you said "Hibernate creates", I assumed you are generating your schema from your entity model. Now it seems it's the opposite, so give it a try.
But instead of a composed primary key on table C, I would like to have a generated ID and a unique constraint on the fields a_id and b_id.
Normally the primary key of the JoinTable is made of the combination of both foreign keys. At least, this is what JPA would generate. But if you don't use the JPA provider to generate the model and if the PK can be generated by the database (using an IDENTITY column, a trigger, etc), then you should be able to use the C table for your ManyToMany association (without having to introduce an extra entity and to transform the relation in two OneToMany). Did you actually try?

Categories

Resources