I have a entity bean with a relation #ManyToOne that is in join on one column.
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) #NotFound (action = NotFoundAction.IGNORE)
#Fetch(FetchMode.JOIN)
#JoinColumn(name = "account", insertable = false, updatable = false, nullable = true)
private AnagraficaClienti account;
And the second Entity
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
....
The "es_account" table has three not nullable primary key(fk_cod_azienda, account, tipo_cli_for) and the relation with the "work_order" table is by account column.
My problem is that sometimes it is possible that the user insert or update WorkOrder with a null account value and that is not avoid by AnagraficaClienti entity because it expects a non null(and not duplicate) value.
Are there any possible way to bypass the join with AnagraficaClienti when account is null?
In my point of view, #ManyToOne is violate OOP design principle due to the creation of redundant relation. Instead, i always create a #OneToMany relation with a list of related entities. To specify the relation as nullable, just add the nullable=true property in #JoinColumn. With #ManyToOne, you must specify property optional=true. Lets try and see if it works.
WorkOrder
#Entity
#Table(name = "work_order")
public class WorkOrder implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#NotNull
#Column(name = "id_order", nullable = false)
private String idOrder;
#Column(name = "description")
private String description;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private StatusOrder status;
#Column(name = "creation_date")
private Instant creationDate;
#Column(name = "closing_date")
private Instant closingDate;
#Column(name = "client_id")
private Long clientId;
AnagraficaClienti
#Entity
#Table(name = "es_account")
public class AnagraficaClienti implements Serializable {
private static final long serialVersionUID = 1L;
// da rimettere a #NotNull
#Column(name = "fk_cod_azienda", nullable = true)
private String fk_cod_azienda;
#Id
#NotNull
#Column(name = "account", nullable = false)
private String account;
// da rimettere a #NotNull
#Column(name = "tipo_cli_for", nullable = true)
private String tipoClienteFornitore;
#Column(name = "tipo_account", nullable = true)
private String tipoAccount;
#OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
#JoinColumn(name = "account", nullable = true)
private List<WorkOrder> workOrders;
When you want to insert the work order to the database:
workOrderRepository.save(workOrder);
When you want to create the relationship:
AnagraficaClienti client = anagraficaClientiRepository.findById(...);
client.getWorkOrders().add(newWorkOrder);
Related
Is it possible to create one column for bi-directional relationship?
My Entities:
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
Now I see two columns in the database and little bit confused.
I don't want to save the same data but want to display a report about how many users visit on some day.
Update:
You are not required to create a separate field "subscription" in VisitDate class. Hibernate will automatically create a field to store subscription id. The code needs to be slightly changed.
#Entity
#Table(name = "subscription")
public class Subscription {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "associatedSub")
private List<VisitDate> visitDates = new ArrayList<>();
}
Notice, that I have changed the mappedBy property to point at associatedSub in the above class.
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
#ManyToOne
#JoinColumn(name="subscription_id")
private Subscription associatedSub;
}
You can use Uni-Directional relationship for the same purpose. You just need to add a list/set of Visits for a particular subscription, You don't have to create a list of subscription for a particular visit.
for reference Visit [Java JPA] :(https://en.wikibooks.org/wiki/Java_Persistence/OneToMany#Undirectional_OneToMany.2C_No_Inverse_ManyToOne.2C_No_Join_Table_.28JPA_2.0_ONLY.29)!
#Entity
#Table(name = "subscription")
#Proxy(lazy = false)
public class Subscription {
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "subscription_id")
private long id;
#Column(name = "userid", nullable = false)
private String userId;
#Column(name = "saledate", nullable = false)
#Temporal(TemporalType.DATE)
private Date saleDate;
#Column(name = "finishdate", nullable = false)
#Temporal(TemporalType.DATE)
private Date finishDate;
#Column(name = "price", nullable = false)
private long price;
#Column(name = "description", nullable = false)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "subscription")
private List<VisitDate> visitDates = new ArrayList<>();
}
#Entity
#Table(name="visitdate")
public class VisitDate {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "id")
private long id;
private long subscription;
#Column(name = "date", nullable = false)
#Temporal(TemporalType.DATE)
private Date date;
}
I am trying to parse a web request and save to database. I have 3 models and first node is virtualDocument. This is the uniq table (according to request url). VirtualRequest table has all erquest bodies and HttpHeaderList table has all thhp headers according to their virtualRequest bean id.
when I tried to save the first log I got and error like this;
org.h2.jdbc.JdbcSQLException: Referential integrity constraint violation: "FK1TW2G47F7A47580KQVMDJWGBQ: PUBLIC.T_VIRTUAL_REQUEST FOREIGN KEY(REQUEST_ID) REFERENCES PUBLIC.T_VIRTUAL_DOCUMENT(DOCUMENT_ID) (65)"; SQL statement:
insert into t_virtual_request (request_id, media_type, method_type, request_url) values (null, ?, ?, ?) [23506-192]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345) ~[h2-1.4.192.jar:1.4.192]
here is VirtualDocument bean
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "request_id")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "response_id")
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
here is VirtualRequest bean;
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "header_id")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
here is HeaderList bean;
#Entity
#Table(name = "t_http_headers")
public class HttpHeaderList {
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
}
I think this is what you want instead:
#Entity
#Table(name = "t_virtual_document")
public class VirtualDocument {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "document_id")
private long documentId;
#Column(name = "real_url", unique = true)
private String realURL; //uniq
#Column(name = "virtual_url", unique = true)
private String virtualURL; //uniq
#Column(name = "simulation_mode", columnDefinition = "varchar(10) default 'STOP'")
private String simulationMode;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
private List<VirtualRequest> requestList;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualDocument")
// Note the mappedBy parameter. This points to the property in the entity that owns the relationship (in this case the VirtualResponse).
private List<VirtualResponse> responseList;
//getter setter without any annotation
}
#Entity
#Table(name = "t_virtual_request")
public class VirtualRequest {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "request_id")
private long requestId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "document_id")
private VirtualDocument virtualDocument;
#Column(name = "request_url")
private String requestURL;
#Column(name = "method_type")
private String methodType;
#Column(name = "media_type")
private String mediaType;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "virtualRequest")
private List<HttpHeaderList> requestHeaders;
//getter setter without any annotation
}
#Entity
#Table(name = "t_http_headers")
public class HttpHeader { /*Note this is a more appropriate name for the entity since it holds the data of a single header.*/
#Id
#Column(name = "header_id")
private long headerId;
#Column(name = "header_key")
private String headerKey;
#Column(name = "header_value")
private String headerValue;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "request_id")
private VirtualRequest virtualRequest
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "response_id")
private VirtualResponse virtualResponse;
}
Updated the answer to add mapping the headers to the request entity.
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "doj")
#Temporal(TemporalType.DATE)
private Date doj;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "id.employee")
private Set<EmployeeProject> employeeProject;
//
Project.java
public class Project implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "project_id")
private Integer projectId;
#Column(name = "exp_end_date")
#Temporal(TemporalType.DATE)
private Date expEndDate;
#Column(name = "project_name")
private String projectName;
#Column(name = "start_date")
#Temporal(TemporalType.DATE)
private Date startDate;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "id.project")
private Set<EmployeeProject> employeeProject;
EmployeeProject.java
#IdClass(EmployeeProjectPK.class)
public class EmployeeProject implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Id
#Column(name = "PROJECT_ID", insertable = false, updatable = false)
private int projectId;
#Id
#Column(name = "employee_id", insertable = false, updatable = false)
private int employeeId;
#ManyToOne
#JoinColumn(name = "employee_id")
private Employee employee;
#ManyToOne
#JoinColumn(name = "project_id")
private Project project;
EmployeeProjectPK.Java
public class EmployeeProjectPK implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Integer projectId;
private Integer employeeId;
Based on above entity design, when I try to persist an 'Employee', I'm getting bellow exception. Any thought?
Caused by: java.lang.ClassCastException: org.hibernate.mapping.SimpleValue cannot be cast to org.hibernate.mapping.Component
I think your problem in mapped by in Employee entity
can you please try using
#OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
private Set<EmployeeProject> employeeProject;
instead of
#OneToMany(cascade = CascadeType.ALL, mappedBy = "id.employee")
private Set<EmployeeProject> employeeProject;
Also try to change it too in Project entity and use
#OneToMany(cascade = CascadeType.ALL, mappedBy = "project")
private Set<EmployeeProject> employeeProject;
instead of
#OneToMany(cascade = CascadeType.ALL, mappedBy = "id.project")
private Set<EmployeeProject> employeeProject;
So finally you should replace
mappedBy = "id.project" by mappedBy = "project"
AND
mappedBy = "id.employee" by mappedBy = "employee"
I following have hibernate entities:
#Entity
#Table(name = "News")
public final class News implements Serializable, IEntity {
private static final long serialVersionUID = 3773281197317274020L;
#Id
#SequenceGenerator(name = "NEWS_SEQ_GEN", sequenceName = "NEWS_SEQ")
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "NEWS_SEQ_GEN")
#Column(name = "NEWS_ID", precision = 0)
private Long newsId; // Primary key
#Column(name = "TITLE")
private String title;
#Column(name = "SHORT_TEXT")
private String shortText;
#Column(name = "FULL_TEXT")
private String fullText;
#Temporal(TemporalType.DATE)
#Column(name = "CREATION_DATE")
private Date creationDate;
#Temporal(TemporalType.DATE)
#Column(name = "MODIFICATION_DATE")
private Date modificationDate;
#OneToMany(cascade = CascadeType.REMOVE, orphanRemoval = true)
#JoinColumn(name = "NEWS_ID", updatable = false, referencedColumnName = "NEWS_ID")
#OrderBy("creationDate ASC")
private List<Comment> commentsList;
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "NEWS_TAG", joinColumns = { #JoinColumn(name = "NEWS_ID") }, inverseJoinColumns = { #JoinColumn(name = "TAG_ID") })
private Set<Tag> tagSet;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "NEWS_AUTHOR", joinColumns = { #JoinColumn(name = "NEWS_ID") }, inverseJoinColumns = { #JoinColumn(name = "AUTHOR_ID") })
private Set<Author> author;
And the second:
#SequenceGenerator(name = "COMMENTS_SEQ", sequenceName = "COMMENTS_SEQ")
#Entity
#Table(name = "Comments")
public class Comment implements Serializable, IEntity {
private static final long serialVersionUID = 3431305873409011465L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "COMMENTS_SEQ")
#Column(name = "COMMENT_ID", precision = 0)
private Long commentId; // Primary key
#Column(name = "NEWS_ID")
private Long newsId;
#NotEmpty
#NotNull
#Column(name = "COMMENT_TEXT")
private String commentText;
#Temporal(TemporalType.DATE)
#Column(name = "CREATION_DATE")
private Date creationDate;
When I'm trying to remove entity News, I get the exception ORA-02292: integrity constraint (ROOT.SYS_C007062) violated - child record found. So, if I remove the property "updatable = false" it tries to set nullable fields into property Comment. What is my mistake? Please, help.
Thanks.
Because your news records have a one to one or one to many relation with comments. You most likely did not specifcy a CACASDE ON DELETE clause while defining your table. in order to delete entity NEWS you have to make sure that all of its related comments records are deleted or are referencing another NEWS record.
basicaly the definition of the ORA 02292 exception.
i have this code
public void guardarAspirante(AspiranteDTO aspiranteDTO) {
Aspirante aspirante = new Aspirante();
String usuarioMovimiento = AspiranteCN.class.getSimpleName();
Date fecha = new Date();
aspirante.setCodigoAlumno(aspiranteDTO.getCodigoUniversitario());
aspirante.setNombre(aspiranteDTO.getNombre());
aspirante.setApellidoPaterno(aspiranteDTO.getPrimerApellido());
aspirante.setApellidoMaterno(aspiranteDTO.getSegundoApellido());
aspirante.setUsuarioMovimiento(usuarioMovimiento);
aspirante.setFechaMovimiento(fecha);
Solicitud solicitud = new Solicitud(aspirante.getSolicitudId());
solicitud.setAspirante(aspirante);
solicitud.setSolicitudId(aspirante.getSolicitudId());
solicitud.setOfertaId(aspiranteDTO.getOfertaAcademica());
solicitud.setPeriodoId(aspiranteDTO.getPeriodo());
solicitud.setAportacion(aspiranteDTO.getAportacionVoluntaria());
solicitud.setFechaMovimiento(fecha);
solicitud.setUsuarioMovimiento(usuarioMovimiento);
aspirante.setSolicitud(solicitud);
....
aspiranteDAO.persist(aspirante);
}
and this error
Internal Exception: java.sql.SQLException: ORA-01400: cannot insert NULL into ("RPINGRE"."ARE_SOLI"."ARE_SOLI_SOLIASPI_ID")
This is Aspirante Entity (Fragment)
#Entity
#Table(name = "ARE_SOLIASPI", catalog = "", schema = "RPINGRE")
public class Aspirante implements Serializable {
private static final long serialVersionUID = 1L;
#SequenceGenerator(sequenceName = "RPINGRE.SQ_ARE_SOLIASPI",
name = "RPINGRE.SQ_ARE_SOLIASPI",
initialValue = 1,
allocationSize = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "RPINGRE.SQ_ARE_SOLIASPI")
#Id
#Basic(optional = false)
#Column(name = "ARE_SOLIASPI_ID")
private Long solicitudId;
#Basic(optional = false)
#Column(name = "ARE_SOLIASPI_CODIGO")
private String codigoAlumno;
#Basic(optional = false)
#Column(name = "ARE_SOLIASPI_NOMBRE")
private String nombre;
#Column(name = "ARE_SOLIASPI_APE_PATERNO")
private String apellidoPaterno;
#Column(name = "ARE_SOLIASPI_APE_MATERNO")
private String apellidoMaterno;
#Basic(optional = false)
#Column(name = "ARE_SOLIASPI_MOV_USUARIO")
private String usuarioMovimiento;
#Basic(optional = false)
#Column(name = "ARE_SOLIASPI_MOV_FECHA")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaMovimiento;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "aspirante", fetch = FetchType.LAZY)
private Solicitud solicitud;
and Solicitud Entity (Fragment)
#Entity
#Table(name = "ARE_SOLI", catalog = "", schema = "RPINGRE")
public class Solicitud implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "ARE_SOLI_SOLIASPI_ID")
private Long solicitudId;
#Basic(optional = false)
#Column(name = "ARE_SOLI_MOV_USUARIO")
private String usuarioMovimiento;
#Basic(optional = false)
#Column(name = "ARE_SOLI_MOV_FECHA")
#Temporal(TemporalType.TIMESTAMP)
private Date fechaMovimiento;
#Column(name = "ARE_SOLI_PERIODO_ID")
private String periodoId;
#Column(name = "ARE_SOLI_OFERTA_ID")
private Long ofertaId;
#Column(name = "ARE_SOLI_APORTACION")
private Long aportacion;
#JoinColumn(name = "ARE_SOLI_SOLIASPI_ID", referencedColumnName = "ARE_SOLIASPI_ID", insertable = false, updatable = false, nullable = false)
#OneToOne(optional = false, fetch = FetchType.LAZY)
private Aspirante aspirante;
.....
}
try changing GenerationType.SEQUENCE to GenerationType.Auto.
The ORA-01400 error says that you are trying to insert a NULL into a column defined as NOT NULL.
I suggest you ether set a default value on the column or have your code make sure the NOT NULL columns have data before you do the INSERT (or use an NVL function in your INSERT statement)