Hibernate relationship issues on no bidirectional entities - java

Hi there I have an entity
OfferItem with this two relationship manyToOne
#ManyToOne
#JoinColumn(name = "offer_id", nullable = false, insertable = false, updatable = false)
#XmlTransient
#Getter
#Setter
private Offer offer;
#ManyToOne
#JoinColumn(name = "item_id", nullable = false, insertable = false, updatable = false)
#XmlTransient
#Getter
#Setter
private Item item;
And the foreign keys configuration on the database
<addForeignKeyConstraint baseTableName="offer_item"
baseColumnNames="item_id"
constraintName="item_offer_item_fk"
referencedTableName="item"
onDelete="CASCADE" onUpdate="CASCADE"
referencedColumnNames="id"/>
<addForeignKeyConstraint baseTableName="offer_item"
baseColumnNames="offer_id"
constraintName="offers_offer_item_fk"
onDelete="CASCADE" onUpdate="CASCADE"
referencedColumnNames="id"
referencedTableName="offer"/>
the relationship with offer is bidireccional, so on the Offer entity I have this relationship with OfferItem
#OneToMany(orphanRemoval = true, cascade = {CascadeType.ALL})
#JoinColumn(name = "offer_id", nullable = false)
#XmlElementWrapper
#Getter
private List<OfferItem> offerItems = new ArrayList<>();
On Item I dont have the bidireccional relationship since is not necessary.
Now the problem is, that when I made the set of Item on OfferItem, and I add the offerItem on the OfferItems list of offer, and I save Offer. I can see how the offerItem id is generated because is persisted on cascade. But the link between the offerItem and item is lost.
I just try to set the item on OfferItem and save the entity with his own service, but nothing. I cannot persist this link between them.
Any idea or suggestion.
Regards.

Remove insertable = false, updatable = false from join columns. Also, the mapping for offerItems is wrong. It should be
#OneToMany(orphanRemoval = true, cascade = {CascadeType.ALL}, mappedBy = "offer")
#XmlElementWrapper
#Getter
private List<OfferItem> offerItems = new ArrayList<>();

Related

Ternary m-to-m-to-m relation in springboot/postgresql

I am trying to implement a ternary relation with the entities Customer, CustomerServant and Room. The teranry relation also has the additional attributes StartDate, EndDate and also an Id. Therefore I created this class to get the relation table:
#Entity(name = "bookings")
#Table(name = "bookings")
public class Bookings {
#Id
#SequenceGenerator(
name = "bookings_sequence",
sequenceName = "bookings_sequence",
allocationSize = 1
)
#GeneratedValue(
strategy = SEQUENCE,
generator = "bookings_sequence"
)
#Column(
name = "bookings_id",
updatable = false
)
private Long Id;
#Column(
name = "Travel_Start_Date",
nullable = false
)
private String travelStartDate ;
#Column(
name = "Travel_End_Date",
nullable = false
)
private String travelEndDate;
#ManyToOne ( cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "customer", insertable = false, updatable = false)
private Customer customer = new Customer();
#ManyToOne
#JoinColumn(name = "room", insertable = false, updatable = false)
private Room room;
#ManyToOne
#JoinColumn(name = "customerServant", insertable = false, updatable = false)
private CustomerServant customerServant;
What I am struggling with is what I should write in the other three classes which are referencing each other.
I do understand that to create a single m-to-m relation with additional relational attributes I can implement a class as I did above and simply write: e.g.
class Bookings {
int Id;
Date StartDate;
Date EndDate;
#ManyToOne
#JoinColumn(name = "customer_id")
Customer customer;
#ManyToOne
#JoinColumn(name = "Room")
Room room;
}
class Customer {
//...
#OneToMany(mappedBy = "customer")
Set<Bookings> bookings;
}
class Room {
#OneToMany(mappedBy = "room")
Set<Bookings> bookings;
but what do I do when I want a ternary relation?
This is how I solved it using the info provided in the article sent by #warmCabin (thorben-janssen.com/ternary-associations):
Using an association table class like above with the attributes startDate, endDate, booking_id and the references to the three entities Room, Customer, CustomerServant, provided that theres an according #ManyToOne annotation for the three referencing entities, just like in the question above.
e.g. like above
#ManyToOne (cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "customer", insertable = false, updatable = false)
private Customer customer = new Customer();
Then I added this to all entities that are connected via the ternary relation:
#OneToMany(mappedBy = "<enter varName from ternary relation table>")
Set<T> var = new HashSet<>();
With this line of code, when a relation is stored e.g. a booking like in my case, this relation gets stored in every participating entity and every stored relation gets the Ids of all participating entities.
In my case it would look like this, for the three entities:
#Entity(name="Room")
#Table(name="Room")
class Room {
//attributes...
#OneToMany(mappedBy = "room")
Set<Bookings> bookings = new HashSet<>();
//...
}
#Entity(name="Customer")
#Table(name="Customer")
class Customer {
//attributes...
#OneToMany(mappedBy = "customer")
Set<Bookings> bookings = new HashSet<>();
//...
}
#Entity(name="CustomerServant")
#Table(name="CustomerServant")
class CustomerServant {
//attributes...
#OneToMany(mappedBy = "customerServant")
Set<Bookings> bookings = new HashSet<>();
//...
}
In the article cited above it is said that its also possible to create such a relation with a HashMap, but because the first appraoch, with an own entity class as a ternary relation, works for me, I didnt check if it would also work in my case. If necessary check the article thorben-janssen.com/ternary-associations.

Is it possible to implement (0..n) many to many (using #ManyToMany annotation) relation in JPA?

I'm looking for a way to implement (0..n) many to many relation in JPA, much possibly using #ManyToMany annotation. All examples that I found were about (1..n) relations. What I need to accomplish:
- I've got two entities: Contact and Tag. Each Contact can have 0..n Tags. Each Tag can have 0..n Contacts. From SQL point of view it would look like
this: Contact (0..n) --- (1) Contact_has_Tag (1) --- (0..n) Tag.
Code below is not working for me because JPA is linking columns with INNER JOIN.
OFC I could do this using intermediate entity and #OneToMany and #ManyToOne annotations, but I want a simpler sollution.
#Data
#Entity
public class Contact {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#JsonIgnore
private long id;
#Column(unique = true)
private String email;
// ...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JsonIgnore
#JoinTable(
name = "contact_has_tag",
joinColumns = #JoinColumn(name = "contact_id", referencedColumnName = "id", updatable = false, nullable = true),
inverseJoinColumns = #JoinColumn(name = "tag_id", referencedColumnName = "id", updatable = false, nullable = true))
private List<ContactTag> contactTags = new ArrayList<ContactTag>();
}
#Entity
#Data
public class ContactTag {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column
private String name;
#ManyToMany(mappedBy="contactTags", fetch = FetchType.LAZY)
#JsonIgnore
private List<Contact> contacts = new ArrayList<Contact>();
}
Any ideas how it should be done?

JPA entity with composite primary and foreign keys

I have an entity with a composite primary key consisting of two fields, one of which is also part of a composite foreign key.
Background: I have entities Person,Area, and Session.
Person has many-to-many relationships with Area and Session, using join entities called PersonArea and PersonSession.
So, I have PersonSession, with primary key of (personId, sessionId).
PersonId and SessionId are themselves foreign keys to Person and Session.
PersonSession also has a field areaId.
I want (personId, areaId) to be a composite foreign key to PersonArea.
My code for PersonSession:
#Entity
#Table(name="person_session")
#IdClass(PersonSession.ID.class)
public class PersonSession {
#Id
private int personId ;
#Id
private int sessionId;
#ManyToOne
#JoinColumn(name = "personId", updatable = false, insertable = false, referencedColumnName = "id")
private Person person;
#ManyToOne
#JoinColumn(name = "sessionId", updatable = false, insertable = false, referencedColumnName = "id")
private Session session;
#ManyToOne//(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "personId", updatable = false, insertable = false),
#JoinColumn(name = "areaId", updatable = false, insertable = false),
})
private PersonArea personArea;
}
Code for PersonSession.Id
public static class ID implements Serializable {
private int personId;
private int sessionId;
}
This seems OK, it creates all the correct relationships in the database. The problem comes when I try to insert PersonSession objects - the areaId column is always null, I think that is because it's defined a updatable=false, insertable=false.
However, if I try and make it updatable and insertable, I get an exception complaining the personId is a repeated column:
Caused by: org.hibernate.MappingException: Repeated column in mapping for entity: foo.bar.PersonSession column: personId (should be mapped with insert="false" update="false")
How can I have the required relationships AND have areaId updatable and insertable?
I should be able to do what I want with this:
#ManyToOne//(cascade = CascadeType.ALL)
#JoinColumns({
#JoinColumn(name = "personId"),
#JoinColumn(name = "areaId", updatable = false, insertable = false),
})
private PersonArea personArea;
But Hibernate does not support mixing updatable and non updatable Join Columns. The accepted answer to this question indicates that it might be supported at some time, but it seems the developers aren't very worried about that shortcoming.
I have how ditched Hibernate in favour of Eclipselink and it works!
I know I am late but I faced the same problem and I used #JoinColumnsOrFormulas to resolve it. Here is what you could do:
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(column = #JoinColumn(name="personId", referencedColumnName = "personId")),
#JoinColumnOrFormula(formula = #JoinFormula(value="areaId", referencedColumnName = "areaId"))})
private PersonArea personArea;

#ManyToMany with cascade = CascadeType.REMOVE removes associations AND entities

I have 2 entities: Group and Grouped, with 1 ManyToMany association.
In database, the Association table has a NOT NULL FK on both Group and Grouped.
I want Hibernate to delete the association but not the group when all grouped are deleted.
Code to delete a Grouped entity:
#Autowired
private final GroupedRepository groupedRepository;
public void delete(Grouped groupedToRemove) {
groupedRepository.delete(groupedToRemove);
}
If I set cascade = CascadeType.ALL or cascade = CascadeType.REMOVE, my Group entities are deleted when I delete a Grouped entity, not only the associations:
#ManyToMany(cascade = CascadeType.ALL, // same behavior with CascadeType.REMOVE
mappedBy = "grouped",
targetEntity = Group.class)
private Set<Group> groups = new HashSet<>();
If I remove the cascade, hibernate tries to set group_id=null and it throws a ModelConstraintException. I don't want to set the FK as nullable.
Group entity:
#Entity
#Table(name = "groups")
#Getter
#Setter
public class Group {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToMany(targetEntity = Grouped.class)
#JoinTable(
name = "association",
joinColumns = #JoinColumn(name = "group_id", nullable = false, updatable = false),
inverseJoinColumns = #JoinColumn(name = "grouped_id", nullable = false, updatable = false)
)
private Set<Grouped> grouped= new HashSet<>();
}
Grouped entity:
#Entity
#Table(name = "grouped")
#Getter
#Setter
public class Grouped {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#ManyToMany(mappedBy = "grouped", targetEntity = Group.class)
private Set<Group> groups= new HashSet<>();
}
That's the expected behavior. REMOVE cascading means: when removing this entity, also remove the associated entities. It makes no sense on a ManyToXxx, since obviously, other entities are still referencing the associated entity.
If you want to delete a Grouped, but leave the associated Groups there, you need to remove the association between the two entities first:
for (Group group : grouped.getGroups()) {
group.getGrouped().remove(grouped);
}
grouped.getGroups().clear();
and then remove the Grouped entity, which is not associated to any Group anymore.

Hibernate mapping with group by clause?

I have #OneToMany mapping in a pojo, and I need to group the resulting list by a column. I have a mapping like the following;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "X", referencedColumnName = "X", insertable = false, updatable = false)
#NotFound(action = NotFoundAction.IGNORE)
#Fetch(FetchMode.SELECT)
public Set<MyType> getSiblings() {
return siblings;
}
I need to add GROUP BY clause to this mapping, is this possible?
I think what you are looking for is support for mapping into a multimap, which is a map with one key and the value is a list of values all associated to the same key.
This is not supported by Hibernate, this is a thread in their forum with an attempt to implement it.
An alternative is to still map to a Set at the property level, and then provide a getter that does the grouping on the fly. This would be transparent for consumers and only become a problem for very large datasets:
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "X", referencedColumnName = "X", insertable = false, updatable = false)
#NotFound(action = NotFoundAction.IGNORE)
#Fetch(FetchMode.SELECT)
private Set<MyType> siblings;
public Map<String,List<MyType>> getSiblings() {
... do the grouping manually in Java ...
}

Categories

Resources