I have three entities who share the same primary key. There is a bidirectional one-to-one relationship between the Account and Provider entity, where the previously named entities share their primary key, but at the same time the Provider entity shares the primary key with the GlobalRating entity, where there is a unidirectional relationship between them. I must say that I am using hibernate with MySQL as a database:
Account Entity:
#Entity
#Table(name="account")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "email")
public class Account implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.AUTO, generator="native")
#GenericGenerator(name = "native", strategy = "native")
#Column(name="id")
private int id;
#OneToOne(mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Provider provider;
}
Provider Entity:
#Entity
#Table(name="provider")
#Getter
#Setter
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "providerId")
public class Provider implements Serializable, Comparable<Provider>{
private static final long serialVersionUID = 1L;
#Id
#Column(name="pk_account$provider")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy="foreign",parameters=#Parameter(name="property", value="account"))
private int providerId;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Account account;
#OneToOne(fetch=FetchType.LAZY, cascade = CascadeType.ALL, optional = false)
#PrimaryKeyJoinColumn
private GlobalRating globalRating;
}
GlobalRating Entity:
#Entity
#Table(name="global_rating")
#Getter
#Setter
public class GlobalRating implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#Column(name="pk_provider$global_rating")
#GeneratedValue(generator="native")
#GenericGenerator(name="native", strategy="foreign",parameters=#Parameter(name="property", value="globalRating"))
private int globalRatingId;
}
The problem that I have is when creating an Account with a Provider and a GlobalRating. I am sure that the bidirectional mapping between Account and Provider works, but the problem lies in the mapping of the entity Provider and the entity GlobalRating. I have tried it in several ways but it does not work. So, how is this case mapped correctly in hibernate?
I appreciate that you can help me with this.
Related
I have three Entities i'm modeling and am having issues with the associated annotations. I basically have a class that I intend on returning to the caller, a nested listed of Project's and the Project can contain a nested list of Endpoint's. It's a top-level has-a one-to-many, then the nested one-to-many has two one-to-many's.
I've played with #JoinColumn annotations, i've attempted to put a #ManyToOne on the other side of the OneToMany's (but it doesn't like that it's a Long..). I'm just fairly new and unsure on how to do this. I think the mappedById is the solution, but i'm uncertain.
Main Issue: This code allows me to "save" to the database, but upon retrieval, the list of Project's inside the DownDetectorPackage is empty.
A CascadeType.ALL throws referential integrity errors that I don't completely understand.
#Data
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Builder
public class DownDetectorPackage {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy="id",fetch = FetchType.EAGER)
private List<Project> projects;
#Temporal(TemporalType.DATE)
private Date dateJobsLastRan;
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Project{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String projectName;
#OneToMany(mappedBy="id")
private List<Service> externalDependencies;
#OneToMany(mappedBy="id")
private List<Service> endpoints;
}
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Service {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String url;
private Boolean endpointIsUp;
private String serviceName;
}
You should be using #JoinColumn instead of mappedBy. MappedBy can be used when you have used #ManyToOne in the other class too, which you haven't.
So your final class should look something like this (this is applicable for the other classes too which you have mentioned) :
public class DownDetectorPackage {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JoinColumn(name = "downDetectorPackageId")
#OneToMany(fetch = FetchType.EAGER)
private List<Project> projects;
#Temporal(TemporalType.DATE)
private Date dateJobsLastRan;
Also, remember to state the parent object name in #JoinColumn annotation, since it would create a column for that foreign key.
You should mark every join column as JoinColumn denotating the referenced column from the other entity. Then, you are supposed to say which relation type are using this column.
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String projectName;
#JoinColumn(referencedColumnName = "id")
#OneToMany(fetch = FetchType.LAZY)
private ExternalDependencyEntity externalDependencies;
#JoinColumn(referencedColumnName = "id")
#OneToMany(fetch = FetchType.LAZY)
private EndpointEntity endpoints;
}
Finally, note that in a relational database, every fk column can takes only 1 value (pk of referenced entity id), so, on your entity, you should mark the data type as the entity you are refering to and no as a collection.
I think this sould solve your problem.
I have the following entity 'User' where the field 'companyId' is a foreign key:
#Entity
#Table(name = "Users")
#Getter #Setter #ToString
public class User {
#Id
#GeneratedValue
private long id;
#Column(name = "company_id")
private Long companyId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id", insertable = false, updatable = false)
private Company company;
The Company entity:
#Entity
#Table(name = "Companies")
#Getter #Setter #ToString
public class Company {
#Id
#GeneratedValue
private long id;
#OneToMany(mappedBy = "company", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY)
private List<User> users;
I removed other irrelevant fields from the classes.
I'm using spring boot data jpa.
My question is how to remove the field 'companyId' and use the company id inside the field 'company' for CRUD functions with the DB.
Simply remove the companyId and make Company writable
#Entity
#Table(name = "Users")
#Getter #Setter #ToString
public class User {
#Id
#GeneratedValue
private long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "company_id")
private Company company;
#Entity
#Data
#NoArgsConstructor
public class Offer {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
#Data
#EqualsAndHashCode
#Entity
#NoArgsConstructor
public class User {
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch=FetchType.LAZY)
private Set<Offer> offers = new HashSet<Offer>();
}
Please help if the mapping is correct in table User and Offer .user_id column have null values ....:(
I'm not sure if these are only parts of the entities but in order for the entity to have an id, you need to provide it with one and annotate the relevant field as #Id.
I also use #GeneratedValue(strategy = GenerationType.IDENTITY) so each table will get it's own id (generated by Hibernate, you don't provide the id when you save a new entity and not a global id, otherwise let's say you add an Offer, you get id with value x, then add new User you get id with value x+1 and so on...
#Entity
#Data
#NoArgsConstructor
public class Offer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
private User user;
}
#Data
#EqualsAndHashCode
#Entity
#NoArgsConstructor
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#OneToMany(mappedBy = "user",cascade = CascadeType.ALL,fetch=FetchType.LAZY)
private Set<Offer> offers = new HashSet<Offer>();
}`
There is a table ORDERS from which were created views ORDER_VIEW_A and ORDER_VIEW_B.
I have created entity classes OrderViewA and OrderViewB where in each of them is mapping on entity named 'TransactionRecord'.
It is #OneToOne relationship.
There is column ORDER_ID in TRANSACTION_RECORD table and field orderId in TransactionRecord entity.
Field orderId is same for OrderViewA.id and for OrderViewB.id, cause views are selected from the same table.
My question is, how to map in Hibernate two views in OneToOne relationship with another entity by same field.
My code looks like this and it doesn't work in any way, Hibernate always end up with:
org.hibernate.AnnotationException: Referenced property not a
(One|Many)ToOne: com.example.app.model.TransactionRecord.orderId in
mappedBy of com.example.app.model.views.OrderViewA.orderViewA
#Entity
#Immutable
#Table(name = "ORDER_VIEW_A")
public class OrderViewA {
#Id
#Column(name = "id")
private Long id;
...
#OneToOne(mappedBy = "orderId", fetch = FetchType.LAZY)
private IntegrationRecord orderARecord;
...
}
#Entity
#Immutable
#Table(name = "ORDER_VIEW_B")
public class OrderViewB {
#Id
#Column(name = "id")
private Long id;
...
#OneToOne(mappedBy = "orderId", fetch = FetchType.LAZY)
private IntegrationRecord orderBRecord;
...
}
#Entity
#Table(name = "TRANSACTION_RECORD")
public class TransactionRecord {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "order_id")
private Long orderId;
...
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private OrderViewA orderViewA;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "order_id")
private OrderViewB orderViewB;
...
}
Hibernate cascade remove doesn't remove child when deleting parent.
causing this error:
ORA-02292: violated integrity constraint (owner.constraintname)- child record found.
Here are my entities:
#Entity
#Table(name = "FLIGHT_MAP_REGION")
#Audited
public class FlightMapRegion extends AbstractBWSModel {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "FLIGHT_MAP_REGION_ID_GENERATOR", sequenceName = "SEQ_FLIGHT_MAP_REGION", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FLIGHT_MAP_REGION_ID_GENERATOR")
private Long ID;
#Column(name = "CODE")
private String code;
// bi-directional one-to-many association to FlightMapRegionI18n
#OneToMany (mappedBy = "flightMapRegion", fetch = FetchType.EAGER, cascade=CascadeType.REMOVE, orphanRemoval=true)
#Fetch(value = FetchMode.SUBSELECT)
#NotAudited
private List<FlightMapRegionI18n> flightMapRegionI18ns;
//getters&setters
and:
#Entity
#Table(name = "FLIGHT_MAP_REGION_I18N")
#Audited
public class FlightMapRegionI18n extends AbstractBWSModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "FLIGHT_MAP_REGION_I18N_ID_GENERATOR", sequenceName = "SEQ_FLIGHT_MAP_REGION_I18N", allocationSize=1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "FLIGHT_MAP_REGION_I18N_ID_GENERATOR")
private Long ID;
#Column(name = "NAME")
private String name;
// bi-directional many-to-one association to flightMapRegion
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "FLIGHT_MAP_REGION_CODE", referencedColumnName="CODE")
#AuditJoinTable
private FlightMapRegion flightMapRegion;
//getters & setters
I want to delete any child FlightMapRegionI18n records when deleting the parent FlightMapRegion record.
Note that these tables are not connected via id, they are connected like this:
FOREIGN KEY (FLIGHT_MAP_REGION_CODE)
REFERENCES FLIGHT_MAP_REGION (CODE)
And I don't want to add ON DELETE CASCADE on database level. I want to achive this programmatically in java.