How to make an entity accessible from two different entities JPA - java

Hi I am new to JPA and i would like to know if it is possible to map two entities to another entity?
For example lets say i have:
-entity1
public class LieuEnseignement implements Serializable {
#Id
#Column(name = "NO_ORGNS", nullable = false)
private Long noOrganisme;
#Column(name = "NO_ADR_GEOGR")
private Long noAdresseGeographique;
#OneToMany(mappedBy="etabEns", cascade = CascadeType.ALL)
private Set<AdresseGeographique> adresseGeographique;
-entity 2
public class EtablissementEnseignement implements Serializable {
#Column(name = "NO_ORGNS", nullable = false)
private Long noOrganisme;
#Column(name="NO_ADR_GEOGR")
private Long noAdresseGeographique;
#OneToMany(mappedBy="etabEns", cascade = CascadeType.ALL)
private Set<AdresseGeographique> adresseGeographique;
-entity 3
public class AdresseGeographique implements Serializable{
#Column(name="NO_ADR", nullable = false)
private Long noAdresse;
#Column(name="LIGNE1_ADR", nullable = false, length = 40)
private String ligne1AdrGeographique;
#Column(name="LIGNE2_ADR", nullable = false, length = 40)
private String ligne2AdrGeographique;
#Column(name="VILLE", nullable = false, length = 46)
private String villeAdrGeographique;
#Column(name="PROV_PAYS", nullable = false, length = 30)
private String provincePaysAdrGeographique;
#Column(name="CD_POSTAL", nullable = false, length = 6)
private String codePostaleAdrGeographique;
#Column(name="CD_MUNICIPALITE", nullable = false, length = 5)
private String codeMunicipaliteAdrGeographique;
#Column(name="POSTN_X", nullable = false)
private String positionXAdrGeographique;
#Column(name="POSTN_Y", nullable = false)
private String positionYAdrGeographique;
#ManyToOne
#JoinColumn(name = "NO_ADR", referencedColumnName = "NO_ADR_GEOGR", insertable=false, updatable=false)
private EtablissementEnseignement etabEns;
#ManyToOne
#JoinColumn(name = "NO_ADR", referencedColumnName = "NO_ADR_GEOGR", insertable=false, updatable=false)
private LieuEnseignement lieuEns;
So basically entity 1 and 2 call to entity 3 never at the same time. I thought i could just declare two seperate joincolumn but apparently this isn't possible.
edit1: As to why I did not use inheritance for entity 1 and 2 is because they are totally different but I did not put all the data contained within them as i did not find it relevent to the question.
Thanks in advance for your help.

Related

Jackson attribute mapping problem with Hibernate

I've researched a lot, but none of the solutions I tried to implement worked... I have the class below, which has many #JoinColumn #ManyToOne relations:
public class Consultas implements Serializable {
#Basic(optional = false)
#Column(name = "status")
private boolean status;
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "idconsultas")
private Integer idconsultas;
#Basic(optional = false)
#Column(name = "data_consulta")
#Temporal(TemporalType.DATE)
private Date dataConsulta;
#Basic(optional = false)
#Column(name = "hora_consulta")
#Temporal(TemporalType.TIME)
private Date horaConsulta;
#JoinColumn(name = "idforma_pagamento", referencedColumnName = "idforma_pagamento")
#ManyToOne(optional = false)
private FormaPagamento idformaPagamento;
#JoinColumn(name = "idfuncionario", referencedColumnName = "idfuncionario")
#ManyToOne(optional = false)
private Funcionario idfuncionario;
#JoinColumn(name = "idpaciente", referencedColumnName = "idpaciente")
#ManyToOne(optional = false)
private Paciente idpaciente;
#JoinColumn(name = "idplano", referencedColumnName = "idplano")
#ManyToOne(optional = false)
private Plano idplano;
When I try to map an instance of this class with the code below, coming from an interface:
JSON.generateJSON(this.consultas, Consultas.class);
The generateJSON method:
public static String generateJSON(Object o, Class valueType)
{
if (valueType == Consultas.class) {
Consultas k = (Consultas) o;
mapper.writeValue(json, k);
}
The output file also brings EVERY attribute from the #JoinColumn#ManyToOne relations (i.e every attribute from the class "Plano","Paciente","FormaPagamento" and "Funcionario"). Why is it mapping all the attributes instead of only the "id" contained inside the Consultas class?
My problem is that I want to write as JSON simply the attributes from the Consultas class, without any additional attributes from its relations.
Maybe it already has an answer, but I couldn't find a proper solution at all. Thanks in advance

Hibernate unexpected deletes when finding entities

We have a Java ee application running on JBoss 6.4 GA using JPA and Hibernate with the following entities:
#Entity
#SequenceGenerator(name = "sequence", sequenceName="SEQ_CAMPAIGNS_ID",allocationSize = 1)
#Table(name = "CAMPAIGN")
public class CampaignEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "IS_ACTIVE", nullable = false)
private boolean active;
#Column(name = "START_DATE", nullable = false)
private Date startDate;
#Column(name = "END_DATE", nullable = false)
private Date endDate;
#Column(name = "LEGAL_ENTITY_ID", nullable = false)
private Integer legalEntityId;
#Column(name = "DEPARTMENT", nullable = false)
#Enumerated(value = EnumType.STRING)
private Department department;
#Column(name = "CATEGORY", nullable = false)
#Enumerated(value = EnumType.STRING)
private Category category;
#Embedded
CampaignConditionsEntity campaignConditions;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "campaign", orphanRemoval = true)
#OrderBy
private List<CodeEntity> campaignCodes;
public CampaignEntity() {
}
And the following CampaignConditionsEntity:
#Embeddable
public class CampaignConditionsEntity implements Serializable {
private static final String CAMPAIGN_ID = "CAMPAIGN_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CAMPAIGN_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CAMPAIGN_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
And the following CodeEntity:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#SequenceGenerator(name = "sequence", sequenceName = "SEQ_CODES_ID", allocationSize = 1)
public abstract class CodeEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CAMPAIGN_ID")
private CampaignEntity campaign;
#OneToOne(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private DiscountEntity discount;
#Column(name = "MAX_USAGES", nullable = false)
private Integer maxUsages;
#Column(name = "UNLIMITED_USAGES", nullable = false)
private boolean unlimitedUsages;
#Column(name = "NEGATIVE_SH", nullable = false)
private boolean negativeSH;
#Column(name = "UNIQUE_BUYER", nullable = false)
private boolean uniqueBuyer;
#Column(name = "START_DATE")
private Date startDate;
#Column(name = "END_DATE")
private Date endDate;
#Embedded
private CodeConditionsEntity codeConditions;
public CodeEntity() {
}
This is the CodeConditionsEntity:
#Embeddable
public class CodeConditionsEntity implements Serializable {
private static final String CODE_ID = "CODE_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CODE_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_CARRIERS", joinColumns = #JoinColumn(name = CODE_ID))
private Set<CarrierConditionEntity> carrierConditions;
This is the CarrierConditionEntity:
#Embeddable
public class CarrierConditionEntity implements Serializable {
#Column(name = "CARRIER", nullable = false, length = 3)
private String carrierCode;
#Column(name = "IS_INCLUDED", nullable = false)
private boolean included;
The problem is that in the logs we are finding unexpected deletes when the only operation that we are doing are finds of particular campaign entities.
In the production logs we find the following deletes
Hibernate: delete from CODE_COND_CARRIERS where CODE_ID=? and CARRIER=? and IS_INCLUDED=?
do you have any suggestion?
thanks
I have some suggestions :)
Be aware of what is a Persistence Context (EntityManager instance in JPA terminology / Session in Hibernate one), the entity lifecycle and transaction scope (unit of work)
Do not mutate entity state if you don't expect the changes to be reflected in database, or at least detach the entity before mutating it.
Mark your transaction as "readOnly" if you only fetch data in the related unit of work. (beware that if you have many "Transactional" methods joining the same physical transaction, the flag is set by the surrounding one and cannot be overridden by inner logical transactions). That way the EntityManager won't be flushed at the end of the transaction and pending changes won't be persisted to the database.
You can track the method triggering the unexpected deletion using an EntityListener on the related entity and printing the current strackTrace (new Throwable().printStackTrace()/ log(new Throwable()) in the PreRemove method
I found where was the problem:
The problem was that the Entities didn't have the equals() and the hashcode() implemented. Also there were entities that have a #PostLoad that modified the entity after loading it from database. Then in this situation Hibernate though that there was a change in those entities that didn't have the equals and the hashcode, and then it delete all of them and inserted again in the database (to have the same entities before the query)
Adding the equals and hashcode methods and deleting postload removed the unexpected deletes and inserts from the logs.
regards

JPA - wrong number of column. should be 2

A Foreign key refering br.com.copagaz.inova.mobile.persistencia.entidade.viagem.nf.NFeProtocolo from br.com.copagaz.inova.mobile.persistencia.entidade.viagem.nf.NfCabeca has the wrong number of column. should be 2
My problem is in one column reference, if i remove #ManyToOne and #JoinColumn(name = "protocolo"), the system works but the selects does not.
i tried to use hibernate.hbm2ddl.auto to auto create the FKs but with no success.
I think the nfe_operacao use a composed PK, and nf_cabeca reference's ii, but did not work.
Any one could help?
#Entity
#Table(name = "nf_cabeca", schema = "mobile", uniqueConstraints =
{#UniqueConstraint(columnNames =
{"NUMERO_FILIAL","serie_nota","numero_nota"})})
public class NfCabeca implements java.io.Serializable {
private static final long serialVersionUID = -921687831233770627L;
#Id
#SequenceGenerator(name = "nf_cabeca_sequencial_seq", sequenceName = "nf_cabeca_sequencial_seq", schema = "mobile", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "nf_cabeca_sequencial_seq")
#Column(name = "sequencial", insertable = false, updatable = false)
private long sequencial;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "data_hora", nullable = false, length = 29)
private Date dataHora;
#Column(name = "valor_total", nullable = false, precision = 17, scale = 17)
private Double valorTotal;
#Column(name = "cancelada")
private Integer cancelada;
#Temporal(TemporalType.DATE)
#Column(name = "data_vencimento", length = 13)
private Date dataVencimento;
#Column(name = "boleto", length = 17)
private String boleto;
#ManyToOne
#JoinColumn(name = "protocolo")
private NFeProtocolo protocolo;
#Column(name = "chave")
private String chave;
#Column(name = "status_nf")
private Integer statusNf;
#Column(name = "status_danfe")
private Integer statusDanfe;
#Column(name = "modelo", length = 3)
private String modelo;
#Column(name = "reconciliada")
private boolean reconciliada = false;
#OneToMany(mappedBy = "nfCabeca", cascade = CascadeType.MERGE)
private List<NfObservacao> nfObservacao;
#OneToMany(mappedBy = "nfCabeca", cascade = CascadeType.ALL)
private List<NfItens> nfItens;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "nf_cabeca")
private List<NFeProtocolo> protocolos = new ArrayList<NFeProtocolo>();
}
This references this table:
#Entity
#IdClass(NFeProtocoloId.class)
#Table(name = "nfe_protocolo", schema = "mobile")
public class NFeProtocolo implements Serializable {
private static final long serialVersionUID = 2092981840170296102L;
#Id
#Column(name = "nf_cabeca", length = 100, insertable = false, updatable = false)
private long nf_cabeca_id;
#Id
#Column(name = "protocolo", length = 100)
private String protocolo;
#Column(name = "operacao", length = 15, nullable = false)
#Enumerated(EnumType.STRING)
private NFeProtocoloOperacao operacao;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "data_hora", length = 29, nullable = false)
private Date dataHora;
#Column(name = "status", length = 10)
private String status;
}
I think the problem is that your #ManyToOne mapping is not correctly declared. As the the entity NFeProtocolo has a composite primary key, you should use #JoinColumns annotation that consists of an array of #JoinColumn annotations:
#ManyToOne
#JoinColumns({#JoinColumn(name = "nf_cabeca_id", referncedColumnName="nf_cabeca_id"),
#JoinColumn(name= "protocolo", referencedColumnName="protocolo")})
private NFeProtocolo protocolo;
You can choose an appropriate name as a foreign key column name.
A Foreign key refering br.com.copagaz.inova.mobile.persistencia.entidade.viagem.nf.NFeProtocolo from br.com.copagaz.inova.mobile.persistencia.entidade.viagem.nf.NfCabeca has the wrong number of column. should be 2
Your problem is simple: Your Entity NFeProtocolo has a composite Id with two columns:
public class NFeProtocolo implements Serializable {
#Id
#Column(name = "nf_cabeca", length = 100, insertable = false, updatable = false)
private long nf_cabeca_id;
#Id
#Column(name = "protocolo", length = 100)
private String protocolo;
But your class NfCabeca is referencing it through only one column:
public class NfCabeca implements java.io.Serializable {
#ManyToOne
#JoinColumn(name = "protocolo")
private NFeProtocolo protocolo;
The solution:
A composite primary key is usually made up of two or more primitive or JDK object types.
As you have a composite key, you should use an Embeddable key, there are many examples about it like this, this and this.

Mapping three identical tables in one entity

i'm needing your help.
i have 3 tables on my database running on postgresql. they are exactly the same structure. so i thought if i could mapp them in one entity.
i try this:
#Entity
#Table(name = "stock_tierra")
#SecondaryTables({
#SecondaryTable(name = "stock_bebelandia"),
#SecondaryTable(name = "stock_libertador")
})
public class Stock implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_stock", unique = true, nullable = false)
private int idStock;
#Column(name = "cantidad", nullable = false)
private int cantidad;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_producto", nullable = false)
private Producto idProducto;
#Column(name = "estado", nullable = false)
private boolean estado;
#Column(name = "usuario_creacion", nullable = false)
private int usuarioCreacion;
#Column(name = "usuario_modificacion")
private Integer usuarioModificacion;
#Temporal(TemporalType.DATE)
#Column(name = "fecha_creacion", nullable = false, length = 13)
private Date fechaCreacion;
#Temporal(TemporalType.DATE)
#Column(name = "fecha_modificacion", length = 13)
private Date fechaModificacion;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_sucursal", nullable = false)
private Sucursal idSucursal;
but when i try to look in to one table i only get data from the first stock_tierra
String stockSucursal = null;
switch (sucursal) {
case 1:
stockSucursal = "stock_tierra";
break;
case 2:
stockSucursal = "stock_bebelandia";
break;
case 3:
stockSucursal = "stock_libertador";
break;
}
Criteria criteria = getSession().createCriteria(Stock.class, stockSucursal);
criteria.add(Restrictions.eq("estado", true));
criteria.addOrder(Order.asc("idStock"));
List<Stock> list = criteria.list();
return list;
some idea what i'm doing wrong?
#SecondaryTables is used to denote one entity being spread over multiple tables in terms of columns, not as a union.
The only thing I can think of right now is using a view which does a union over all the tables, but I am not sure whether postgres can handle writable views, or how you declare them (if you even need a write interface.)

Hibernate MS SQL Join issue

I have two tables in the clients mssql database. The first is a job table - so I created an Job entity which contains the load type and load weight and all that stuff - works fine.
My problem now is that there is a second table that includes informations about the load and unload point. The second table, I call it JEP, has a primary key consisting of several items: the type (load or unload), the zip code and the customer number.
I created an entity JobEndPoint and NetBeans also created an object representing the primary key JobEndPointPK containing all that fields.
I want to add two JobEndPoint (loadPoint and unloadPoint) to my Job entity. My problem is now: how do I annotate that in Hibernate? In my opinion it is an #OneToOne relation ship. It would be perfect if I could specify a SELECT statement like SELECT * FROM JEP WHERE type="load" AND customer_nr="123" AND zip_code="123 ...". Is that possible with Hibernate?
Thanks for your help!
Regeards,
Marco
Here are the Entities:
#Entity
#Table(name = "Auftragsdaten", catalog = "...", schema = "dbo")
public class Job implements Comparable<Object>, Serializable {
private static final long serialVersionUID = 4285871251915951149L;
#Id
#Basic(optional = false)
#Column(name = "`id`", nullable = false)
int id;
#Column(name = "`AufNr`", nullable=false)
int jobId;
#Transient
List<Integer> jobsAdded;
#Column(name = "`Beladedatum`", nullable=false)
#Temporal(TemporalType.DATE)
Date loadDate;
#Column(name = "`Beladezeit`")
#Temporal(TemporalType.TIME)
Date loadTimeFrom;
#Transient
Date loadTimeTo;
#Column(name = "`Entladedatum`", nullable=false)
#Temporal(TemporalType.DATE)
Date unloadDate;
#Column(name = "`Entladezeit Beginn`")
#Temporal(TemporalType.TIME)
Date unloadTimeFrom;
#Column(name = "`Entladezeit Ende`")
#Temporal(TemporalType.TIME)
Date unloadTimeTo;
#Transient
List<JobEndPoint> froms;
#OneToOne
#JoinColumns ({
#JoinColumn(name="`Beladetyp`", referencedColumnName = "`Ladetyp`", insertable = false, updatable = false),
#JoinColumn(name="`AbsNr`", referencedColumnName = "`KundenNr`", insertable = false, updatable = false),
#JoinColumn(name="`Verkehrsart`", referencedColumnName = "`VerkArt`", insertable = false, updatable = false),
#JoinColumn(name="`von LKZ`", referencedColumnName = "`LKZ`", insertable = false, updatable = false),
#JoinColumn(name="`von PLZ`", referencedColumnName = "`PLZ`", insertable = false, updatable = false)
})
JobEndPoint fromPoint;
#Transient
JobEndPoint toPoint;
#Column(name = "`Verkehrsart`", length = 10, nullable=false)
#Enumerated
JobType type;
#Column(name = "`Anzahl Paletten CCG1`")
int numberCCG1;
#Column(name = "`Anzahl Paletten CCG2`")
int numberCCG2;
#Transient
int numberFullContainer;
#Transient
int numberEmptyContainer;
#Column(name = "`Anzahl Container`")
int numberContainer;
#Column(name = "`Anz Stellplätze`")
int numberUnits;
#Column(name = "`Bruttogewicht`", nullable=false)
int loadWeight;
#ManyToOne
#JoinColumn(name="`Kühlkennzeichen`")
CoolingCode coolingCode;
}
#Entity
#Table(name = "BES", catalog = "...", schema = "dbo")
public class JobEndPoint implements Serializable {
private static final long serialVersionUID = 1017986852824783744L;
#Id
protected JobEndPointPK jobEndPointPK;
(...)
}
#Embeddable
public class JobEndPointPK implements Serializable {
#Basic(optional = false)
#Column(name = "`Ladetyp`", nullable = false, length = 50)
#Enumerated
EndPointType type;
#Basic(optional = false)
#Column(name = "`KundenNr`", nullable = false)
int customerId;
#Basic(optional = false)
#Column(name = "`VerkArt`", nullable = false, length = 10)
#Enumerated
JobType jobType;
#Basic(optional = false)
#Column(name = "`LKZ`", nullable = false, length = 3)
String countryCode;
#Basic(optional = false)
#Column(name = "`PLZ`", nullable = false, length = 7)
String zipCode;
}
In general, I would recommend using a generated internal primary key instead of the composite key. However, if you need to stick with your composite key, here are some ideas that hopefully help.
I understand that JobEndPointPK is implemented as an identifier component (see the Hibernate Reference, chapter 8.4). Note: it is critical that it implements the equals and hashCode` methods correctly, as Hibernate relies on these.
Updated: Provided that your JobEndPoint and JobEndPointPK looks something like this:
#Embeddable
class JobEndPointPK {
#Column(name = "type", nullable = false)
#Enumerated
EndPointType type;
#Column(name = "zipCode", nullable = false)
String zipCode;
#Column(name = "customerNumber", nullable = false)
int customerId;
// equals, hasCode, getters, setters etc.
}
#Entity
class JobEndPoint {
#Id
private JobEndPointPK key;
// getters, setters etc.
}
The mapping annotation would be something like:
#Entity
class Job {
#OneToOne
#JoinColumns ({
#JoinColumn(name="loadPointType", referencedColumnName = "type"),
#JoinColumn(name="loadPointZip", referencedColumnName = "zipCode"),
#JoinColumn(name="loadPointCust", referencedColumnName = "customerNumber")
})
private JobEndPoint loadPoint;
// similarly for unloadPoint
// other properties
}
The example is adapted from here.
I am not sure how to deal with JobEndPointPK.type though, as for loadPoint it is obviously Load and for unloadPoint, Unload, so you most probably don't want to store it separately in the DB. My gues is that you can specify the value with the #Formula annotation, but I haven't seen any concrete example for this.
Note that all this code is purely experimental, I haven't tested it.
There are other variations on the theme. For more details, see the section "Composite keys with annotations" in Chapter 8 of Java Persistence with Hibernate.

Categories