Mapping composite key with Hibernate produces a raw field in Oracle - java

-- The Facts....
In my project every class/table should have a couple (Site,Structure) in order to provide multisite deploy.
I provided an Installation class
#Entity
#Table(name="COM_INSTALLATION")
#IdClass(InstallationPK.class)
public class Installation implements Serializable{
private static final long serialVersionUID = 3601006283578715263L;
#Id
#Column(name = "site")
private String site;
#Id
#Column(name = "structure")
private String structure;
/* ... constructor, getters, setters ... */
}
and its PK, as
public class InstallationPK implements Serializable {
private static final long serialVersionUID = 1L;
private String site;
private String structure;
/* .. constructor, getters, setters ... */
}
then I have a MappedSuperclass named BaseEntity
#MappedSuperclass
public class BaseEntity
{
private Installation installation;
#OneToOne
#JoinColumns({
#JoinColumn(name = "site", referencedColumnName = "site"),
#JoinColumn(name = "structure", referencedColumnName = "structure")
})
public Installation getInstallation() {
return installation;
}
public void setInstallation(Installation installation) {
this.installation = installation;
}
}
quite easy so far... every #Entity and #Table annotated class extending BaseEntity contains a column SITE, a column STRUCTURE and a related foreign key.
-- The Problem....
It happens that with a class implementing org.springframework.security.core.userdetails.UserDetails and extending BaseEntity, Hibernate does not create the two columns but an INSTALLATION column with RAW type. That's the class
#Entity
#Table(name="USR_USER", uniqueConstraints =
#UniqueConstraint(columnNames = { "username" }))
#SequenceGenerator(name = "userId_seq_generator", sequenceName = "S_USER")
public class User extends BaseEntity implements UserDetails{
private static final long serialVersionUID = 8698408700004341649L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "userId_seq_generator")
private Long userId;
/* ... getter, setters, ... */
}
and that's the result
Any ideas? Thanks in advance

I don't have point reputation to comment so i'll put here my comments:
Why instalationPK field isn't in instalation.class??
You should put #EmbeddedId in the field instalationPK in Installation.class.
I don't if makes differences, but put joinCollums on the field in BaseEntity:
#OneToOne
#JoinColumns({
#JoinColumn(name = "site", referencedColumnName = "site"),
#JoinColumn(name = "structure", referencedColumnName = "structure")
})
private Installation installation;

Related

How to remove foreign key without deleting the whole entity

I am new to Spring boot and I want to be able to delete the value of a forgein key if its entity is removed without deleting the whole entity linked to it; I explain in my case a single person who has an Account can be at the same time an Author and a Player, so if I delete an author I want to delete its refrence in Account table without deleting the whole account because this account can still point on player. I searched on the internet I found cascadetype but it will delete the whole account!
Thank you in advance!
here is my entities
#Table(name = "account")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
#ManyToOne
#JoinColumn(name = "Author")
private Author author;
#ManyToOne
#JoinColumn(name = "Player")
private Player player;
//attributs, getters & setters
}
#Table(name = "player")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
//attributs, getters & setters
}
//ma.myapp.usersgestion.domain.Author
#Table(name = "author")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
#OneToMany(mappedBy = "author")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#JsonIgnoreProperties(value = { "player", "author"}, allowSetters = true)
private Set<Account> accounts = new HashSet<>();
//attributs, getters & setters
}
UPDATE
Im using jhipster (spring boot with React) and h2 database (with disk-based persistence)
//AuthorResource.java
#RestController
#RequestMapping("/api")
#Transactional
public class AuthorResource {
private final Logger log = LoggerFactory.getLogger(AuthorResource.class);
private static final String ENTITY_NAME = "author";
#Value("${jhipster.clientApp.name}")
private String applicationName;
private final AuthorRepository authorRepository;
public AuthorResource(AuthorRepository authorRepository) {
this.authorRepository = authorRepository;
}
/**
* {#code DELETE /authors/:id} : delete the "id" author.
*
* #param id the id of the author to delete.
* #return the {#link ResponseEntity} with status {#code 204 (NO_CONTENT)}.
*/
#DeleteMapping("/authors/{id}")
public ResponseEntity<Void> deleteAuthor(#PathVariable Long id) {
log.debug("REST request to delete Author : {}", id);
authorRepository.deleteById(id);
return ResponseEntity
.noContent()
.headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()))
.build();
}
//...
}
//AuthorRepository
#SuppressWarnings("unused")
#Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {}
In your entity class author add the following:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "author", cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST })
private Set<Account> accounts;
I've omitted the cascadetype CascadeType.REMOVE from the list. This will prevent Account from also being deleted when the related Author entity is deleted.
EDIT:
If the above solution somehow doesn't work then you can also try adding #OnDelete(action = OnDeleteAction.NO_ACTION) above the accounts field.
#OnDelete is a hibernate specific annotation.
EDIT 2:
If none of the solutions provided above work then you can also consider making a javax.persistence.#PreRemove annotated method that manually sets the author field for each related Account to null. You place this method inside the Author class. A method that is annotated with #PreRemove will always run before the entity is deleted. So for Author you could use the following method to set all author_id fields to null.
#PreRemove
public void deleteAuthor(){
this.getAccounts().forEach(account -> account.setAuthor(null));
}

How to maintain foreign key relationship in hibernate

I have two classes and I want to have a one to many relation between them, for e.g.:
Home(id<int>, rooms<string>)
Vehicle(id<int>, home_id<int>, name<string>)
I need to have a relation between Home and Vehicle class using Home.id and vehicle.home_id.
Please suggest any example which I can use here for CURD operation to implement REST service.
I need to have a relation between Home and Vehicle class using Home.id
and vehicle.home_id.
Your entities should look like this :
Vehicle Entity
#Entity
#Table(name = "vehicle", catalog = "bd_name", schema = "schema_name")
#XmlRootElement
public class Vehicle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#JoinColumn(name = "home_id", referencedColumnName = "id")
#ManyToOne
private Home homeId;
//constructor getter & setters
}
Home Entity
#Entity
#Table(name = "home", catalog = "bd_name", schema = "schema_name")
#XmlRootElement
public class Home implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "room")
private Character room;
#OneToMany(mappedBy = "homeId")
private List<Vehicle> vehicleList;
//constructor getter & setters
}

Hibernate merge parent and update Lazy Child Collection List

I am having a problem when I perform merge parent table, the existing child records will be insert rather than update.
For example, Member(Parent) and Address(Child) tables,
public class Member implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="id")
private int id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "member", cascade = CascadeType.ALL)
public List<Address> addressList;
}
public class Address implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int address_id;
#Column(name = "member_id")
private int mem_id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "member_id", referencedColumnName = "id", insertable = false, updatable = false)
})
public Member member;
}
While I perform changes and merge(Member), the address record is being inserted rather than update the existing record.
Does anyone know what would be the reason?
when you perform changes do you set correct address_id ? . Do some debugging and find address_id match with existing id in Address table.
in my approach class will look like below. I don't see need of member_id attribute. because it is same as id attribute of member.
public class Address implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int address_id;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "member_id", nullable = false)
public Member member;
public void setMember(Member member) {
this.member = member;
}
}
I can't see any parent child relationship in your snapshot code.
Please amend the code for child class with below code to create the inheritance relationship.
public class Child extends Member implements Serializable{
Extending the Child class to the Parent(Member) will reflect the required changes related to lazy loading.

jpa one-to-many self reference is fetching all levels

I'm trying to create a social app service. I have user with confirmed or nonconfirmed relationships.
When I load UserA, the result look like belove.
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":[
{
"idUser":"UserC",
"unconFriendships":[
...
While it has to be look like
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":null //only one level have to fetched
....
I thought that this was because jackson json library, I debbuged the code. Before serialization, I inspected userA object and I saw that userA.unconFriendships.userB.unconFriendships was not null and with size bigger than 0.
Nearly it has been 12 hours, still couldn't solve the problem. Please help me to solve this. Thanks in advence.
Here is UserEntity.java
#Entity
#Table(name="aduser",uniqueConstraints=#UniqueConstraint(columnNames = {"idUser","nmEmail"}))
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="cdUser")
public class UserEntity extends BaseEntity {
protected static final long serialVersionUID = 8864033727886664353L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "admin_seq")
#SequenceGenerator(name = "admin_seq", sequenceName = "CDUSER_SEQUENCE", allocationSize = 1)
#Column(name="cdUser")
private long cdUser;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> unconFriendships;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> conFriendships;
...
Friendship.java
#Entity
#Table(name="aduserfriend")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "verified")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="friend_cduser",scope=UserEntity.class)
public abstract class Friendship extends BaseEntity{
protected static final long serialVersionUID = -670863816551430192L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "cdFriendship")
private long cdFriendship;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "owner_cduser")
protected UserEntity owner;
#ManyToOne
#JoinColumn(name = "friend_cduser")
protected UserEntity friend;
#Column(name = "verified",insertable=false,updatable=false)
private boolean verified;
...
UnconfirmedFriendship.java and ConfirmedFriendship.java
#Entity
#DiscriminatorValue(value = "0")//this value is 1 for Confirmed relationship
public class UnconfirmedFriendship extends Friendship {
private static final long serialVersionUID = 57796452166904132L;
}

Use Composite key as a Foreign key in JPA gives an error

I have two composite keys in this class (module, instrumentType)
#Entity
#Table(name = "aa_bank_instruments")
#IdClass(InstrumentsComposite.class)
public class Instruments extends Model {
/**
*
*/
private static final long serialVersionUID = -8401839630224674535L;
#Id
#JoinColumn(name = "module_id")
#ManyToOne(cascade = CascadeType.ALL)
private Module module;
#Id
#Column(name = "instrument_type")
private String instrumentType;
#Column(name = "descritpion")
private String descritpion;
//getters & setters
}
In the following class, I have a foreign a key referencing to ONE of a composite key in the above class. (module and instruments are composite in this class)
#Entity
#Table(name = "aa_bank_functions")
#IdClass(FunctionsComposite.class)
public class Functions extends Model{
/**
*
*/
private static final long serialVersionUID = -1162529578613327377L;
#Id
#Column(name = "function_id")
private String functionId;
#Id
#JoinColumn(name = "instrument_type", referencedColumnName="instrument_type")
#ManyToOne(cascade = CascadeType.ALL)
private Instruments instruments;
#Column(name = "description")
private String description;
}
Now the problem is I can't persist Functions to the DB when I tries, It gives the following error
Caused by: org.hibernate.AnnotationException: A Foreign key refering com.fg.banking.model.Instruments from com.fg.banking.model.Functions has the wrong number of column. should be 2
Does anybody know the reason? Thanks in advance.....

Categories