i have a persit problem with elcipselink
here is my model :
#Entity
#Table(name = "TBL_ASSOC_LANGUE_CODE_BE_GARE")
public class AssocLangueCodeBeGare {
#AttributeOverrides({ #AttributeOverride(name = "id_langue", column = #Column(name = "ID_LANGUE") ),
#AttributeOverride(name = "id_gare", column = #Column(name = "ID_GARE") ) })
#EmbeddedId
private AssocLangueCodeBeGareFK key;
#Column(name = "CODE_BE", length = 4)
private String codeBe;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "ID_GARE", referencedColumnName = "ID_GARE", insertable = false, updatable = false)
private StopPoint stopPoint;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_LANGUE", referencedColumnName = "ID_LANGUE", insertable = false, updatable = false)
private Langue langue;
in StopPoint i don t reference table AssocLangueCodeBeGare, i don t need it.
then when i do :
this.serviceStopPoint.save(currentStopPoint);
for (AssocLangueCodeBeGare assoc : listAssocLangueCodeBeGare) {
assoc.setStopPoint(currentStopPoint);
this.serviceAssocLangueCodeBeGare.save(assoc);
}
save is
#Override
public void save(T entityToSave) {
this.getEntityManager().persist(entityToSave);
}
I m using batch insert for writing and sometimes when i save another entity flush is done and i get :
Caused by: org.h2.jdbc.JdbcBatchUpdateException: NULL not allowed for column "ID_GARE"; SQL statement:
INSERT INTO TBL_ASSOC_LANGUE_CODE_BE_GARE (CODE_BE, ID_GARE, ID_LANGUE) VALUES (?, ?, ?) [23502-192]
at org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1208)
at org.eclipse.persistence.internal.databaseaccess.DatabasePlatform.executeBatch(DatabasePlatform.java:2134)
at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeJDK12BatchStatement(DatabaseAccessor.java:871)
does i miss something in the mapping?
does i need to add something like this in stoppoint entity:
#OneToMany(mappedBy = "stopPoint", cascade = CascadeType.ALL)
List<AssocLangueCodeBeGare> assocLangueCodeBeGares;
#EDIT1
I think its caused by my EmbeddedId because it was null!! the mapping does'nt set correct value in the embedable object?
here is the embedable object :
#Embeddable
public class AssocLangueCodeBeGareFK implements Serializable {
private String id_langue;
private Long id_gare;
#Override
public int hashCode() {
thanks a lot!
The insertable = false and updatable = false prevent the value from the mapping from being written to the database. You need to have another mapping to that database column with the value set, or it won't get into the database. While making your OneToMany the ID works, so would the MapsId annotation in the current code as JPA will then set the value in your embeddable ID. Or you could have manually added the value from the referenced class into the appropriate AssocLangueCodeBeGare.key fields.
Finaly i find a solution :
I use #IdClass(AssocLangueCodeBeGareFK.class on AssocLangueCodeBeGare
And i put #id on
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(nullable = false, name = "ID_GARE", referencedColumnName = "ID_GARE")
private StopPoint stopPoint;
#Id
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ID_LANGUE", referencedColumnName = "ID_LANGUE")
private Langue langue;
I rename on my AssocLangueCodeBeGareFK class name of my property to be the same as the AssocLangueCodeBeGare class :
private Long stopPoint;
private String langue;
now all work like a charm.
if it helps...
Related
I have two tables Company and Employees, one-to-many mapping. Company table contains composite primary key.
I want to search from company table based on primary id but want to put an additional check on the child table.
I want to load only a particular type of employees which I will get in the request. How it can be done in Sprongboot JPA with findById("id");
class Company{
#Id
private String companyId;
#Id
private String stateId;
private String company Name;
#OneToMany(targetEntity = Employees.class, fetch = FetchType.LAZY, cascade = {
CascadeType.ALL }, mappedBy = "company")
private Set<Employees> empList;
}
class Employees{
#Id
private String id;
//foreign key
private String companyId;
//foreign key
private String stateId;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "companyId", referencedColumnName = "companyId", insertable = false, updatable = false, nullable = true),
#JoinColumn(name = "stateId", referencedColumnName = "stateId", insertable = false, updatable = false, nullable = true) })
private Company company;
private int salary;
private String type;
}
Use Filter, which is an alternative of #Where where you can set dynamic value.
Here is the sample
#FilterDef(
name = "employeeTypeFilter",
parameters = #ParamDef(name = "type", type = "string")
)
#Filter(
name = "employeeTypeFilter",
condition = "type > : type"
)
public class Employees {
}
You can enable or disable filter from your code dynamically based on your requirement.
You can use #Where for fixed type
#Where(clause = "type = 'anyEmployeeType'")
private Set<Employees> empList;
For dynamically fetch you can query in Employees repository
List<Employees> findByTypeAndCompany(String type, Company company);
In my project I use Spring data jpa. I have tables for many to many relationship. My entities:
#Entity
#Table(name = "SPEC")
public class SpecJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "Creator_ID", unique = false, nullable = false, updatable = true)
private UsersJpa usersJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(name="SPEC_PARTS",
joinColumns = #JoinColumn(name="ID_PARTS", referencedColumnName="id"),
inverseJoinColumns = #JoinColumn(name="ID_SPEC", referencedColumnName="id")
)
private Set<PartsJpa> partsJpa;
//---------------
And Parts:
#Entity
#Table(name = "PARTS")
public class PartsJpa {
#Id
private int id;
#Column(name = "NAME")
private String name;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_EXPORT", unique = false, nullable = false, updatable = true)
private ExportJpa exportJpa;
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "ID_TYPE", unique = false, nullable = false, updatable = true)
private TypesJpa typesJpa;
#Column(name = "DESCRIPTION")
private String description;
#ManyToMany(fetch = FetchType.EAGER)
private Set<SpecJpa> specJpa;
Now in Controller I try to delete one row from table parts:
#PostMapping("deletePart")
public String deletePart(#RequestParam String id, Model model) {
partsService.deleteById(Integer.parseInt(id));
return "redirect:/parts";
}
But I have exception:
ferential integrity constraint violation:
"FK9Y4MKICYBLJWPENACP4298I49: PUBLIC.PARTS FOREIGN KEY(ID_EXPORT)
REFERENCES PUBLIC.EXPORT(ID) (1)"; SQL statement: /* delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa / delete from EXPORT
where id=? [23503-200]], SQL: / delete
com.aleksandr0412.demo.entitiesjpa.ExportJpa */ delete from EXPORT
where id=? 2020-05-25 19:16:31.630 WARN 13387 --- [nio-8080-exec-4]
o.h.engine.jdbc.spi.SqlExceptionHelper : SQL Error: 23503, SQLState:
23503
In my db for this entities I have 3 tables: Parts, Spec and Spec_parts. As I understand to solve this problem, I firstly should delete rows in table spec_parts, and after this I can delete row from table parts. How can I do this?
In your partsService implementation, I would recommend you first fetch the resource you are about to delete (i.e the PartsJpa) using the given id from the controller.
Next set its specJpa to null or emptySet, then call the delete method afterwards.
For this to work, ensure that method setSpecJpa(SpecJpa specJpa) and setPartJpa(PartJpa partJpa) are properly implemented.
I hope you find this helpful.
In my project I have to connect to existing database and do logic which updates two tables.
My setup is following:
#Entity
#Table(name = "DOCUMENTCONTENT")
#Getter
public class DocumentContent {
#Id
#Column(name = "ID", insertable = false, updatable = false)
private Long id;
#OneToOne
#JoinColumn(name = "DOCUMENT_ID", insertable = false, updatable = false)
private Document document;
#Lob
#Column(name = "CONTENT")
#Setter
private byte[] content;
}
#Entity
#Table(name = "DOCUMENT")
#Getter
public class Document {
#Id
#Column(name = "ID", insertable = false, updatable = false)
private Long id;
#OneToOne(mappedBy = "document")
private DocumentContent documentContent;
#OneToMany(mappedBy = "document", fetch = EAGER)
private List<Attachment> attachments;
}
#Entity
#Table(name = "ATTACHMENT")
#Getter
public class Attachment {
#Id
#Column(name = "ID")
private Long id;
#ManyToOne
#JoinColumn(name = "DOCUMENT_ID", insertable = false, updatable = false)
private Document document;
#ManyToOne
#JoinColumn(name = "CONTRACT_ID",updatable = false, insertable = false)
private Contract contract;
}
#Entity
#Table(name = "CONTRACT")
#Getter
public class Contract {
#Id
#Column(name = "ID", insertable = false, updatable = false)
private Long id;
#Column(name = "STATUS")
#Setter
private String status;
#ManyToOne
#JoinColumn(name = "CUSTOMER_ID", insertable = false, updatable = false)
private Customer customer;
#OneToMany(mappedBy = "contract", fetch = EAGER)
private List<Attachment> attachments;
}
#Service
public class MyServiceImpl implements MyService {
#Autowired
private DocumentContentRepository documentContentRepository; // spring data Crud Repository
#Override
#Transactional
public void updateDocumentContent(SomeDto someDto) {
DocumentContent documentContent = documentContentRepository.findByDocumentId(someDto.getDocumentId());
documentContent.setContent(someDto.getBytes());
List<Contract> contracts = documentContent.getDocument().getAttachments()
.stream().map(Attachment::getContract).collect(toList());
contracts.forEach(contract -> contract.setStatus("SIGNED"));
documentContentRepository.save(documentContent);
}
}
When I fire method from above service I can notice those SQL in console output:
Hibernate: update documentcontent set content=? where id=?
Hibernate: update contract set status=? where id=?
I understand why jpa performed first update in documentcontent table, but I don't know why it did update in contract table aswell. As you can see I didn't use CascadeType.MERGE in any entity.
Can you explain me why this second update has been performed without declaring cascade type?
I doubt it has anything to do with Cascade at all, but with transactional write behind mechanism (more info). I believe you could also get rid of the line
documentContentRepository.save(documentContent);
since you are modifying two managed entities. At the end of the transaction hibernate persists all entities marked as modified by the dirty checking mechanism (more info).
You are getting 2nd query for the reason, you are modifying Status property of Contract.
JPA detect this change and try to update entity.
This is default CaseCadeType behaviour of #OneToMany
For further reading follow this link.
I have the following model that I need to annotate using JPA:
Merchant(merchant_id, ...).
MerchantType(id1, id2, ...)
MerchantMerchantTypeAssociationTable(merchant_id, id1, id2)
I cannot figure out how to map the association table. Mapping Merchant is straitghtforward, so I will leave it outside of the mappings. The other mappings are as follows:
MerchantType:
#Entity
class MerchantType {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column=#Column(name="e1_id")),
#AttributeOverride(name = "another_id", column=#Column(name="another_id"))
})
MerchantTypePk id;
#ManyToOne
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, nullable = false)
#MapsId("e1_id")
AnotherEntity1 e1;
#Column(name = "another_id", referencedColumnName = "another_id", insertable = false, nullable = false)
Long anotherId;
//Two other local fields irrelevant to the discussion here
public MerchantType(){
this.id = new MerchantTypePk();
}
//Getters and setters here.
}
//MerchantTypePk is a simple Embeddable class here below with two Long fields:
//e1_id and another_id
MerchantMerchantTypeAssociation:
#Entity
class MerchantMerchantTypeAssociation {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "e1_id", column = #Column(name = "e1_id")),
#AttributeOverride(name = "another_id", column = #Column(name = "another_id"))
#AttributeOverride(name = "offer_id", column = #Column(name = "merchant_id"))
})
private MerchantMerchantTypeAssociationPk id;
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
//******** HERE IS THE QUESTION
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id", insertable = false, updatable = false),
#JoinColumn(name = "another_id", referencedColumnName = "another_id", insertable = false, updatable = false)
})
#MapsId("e1_id")
#MapsId("another_id")
private MerchantType merchantType;
//Similar mapping to the one above, but with only one Join Column
private Merchant merchant;
//One more local field that is irrelevant to the mapping
//but is the one that is forcing me to map a many - to - many relationship
//in this way.
}
//MerchantMerchantTypeAssociationPk as a simple embeddable
Question: How can I make a mapping for this kind of entities when the annotation '#MapsId' cannot be repeated and it does not accept more than one value?
You did not include the code for MerchantMerchantTypeAssociationPk, but I'm guessing it looks like this:
#Embeddable
public class MerchantMerchantTypeAssociationPk {
public MerchantPk merchantPK;
public MerchantTypePk merchantTypePK;
}
#MapsId is used to specify the attribute within the composite key to which the relationship attribute corresponds, not the columns. So MerchantMerchantTypeAssociation should look like this:
#Entity class MerchantMerchantTypeAssociation {
#EmbeddedId
private MerchantMerchantTypeAssociationPk id;
#ManyToOne
#JoinColumns({
#JoinColumn(name = "e1_id", referencedColumnName = "e1_id",...),
#JoinColumn(name = "e2_id", referencedColumnName = "e2_id",...)
})
#MapsId("merchantTypePK") // <<< *attribute* in Embeddable
private MerchantType merchantType;
#ManyToOne
#JoinColumn(name = "m_id", referencedColumnName = "merchant_id",...)
#MapsId("merchantPK") // <<< *attribute* in Embeddable
private Merchant merchant;
}
Derived identities are discussed in the JPA 2.1 spec, section 2.4.1.
I'm having a problem that I don't know if it's possible to solve just by using hibernate/jpa annotations. The problem is that I have a composite key that has the same column as one of my foreignkey composite id, and I would like to share this same column on the table. For example:
#Entity
class Id {
#Id
#Column(name = "idPessoa")
public Integer idShared;
}
#Embeddable
class APK {
#ManyToOne
#JoinColumn(name = "idShared")
public Id idShared;
public String nKey;
}
#Entity
class A {
#EmbeddedId
public APK id;
}
#Embeddable
class BPK {
#ManyToOne
#JoinColumn(name = "idShared")
public Id idShared;
public Integer nCode;
}
#Entity
class B {
#EmbeddedId
public BPK id;
#ManyToOne
#JoinColumns({ #JoinColumn(name = "idShared", nullable = false, insertable = false, updatable = false), #JoinColumn(name = "nKey", nullable = false) })
public A a;
}
The question is how I can share the column idShared between A and B and use it in the #ManyToOne for the foreign key?
I already tried to use #JoinColumn inside #JoinColumns with the name idShared but I get an error saying that I need to use insert = false and update = false, I already put insertable = false and updateable = false, but then I get another error saying that I can't mix things.
I found a possible solution saying to use:
#ManyToOne
#JoinColumnsOrFormulas(value = {
#JoinColumnOrFormula(formula = #JoinFormula(value = "idShared", referencedColumnName = "idShared")),
#JoinColumnOrFormula(column = #JoinColumn(name = "nKey", nullable = false)) })
public A a;
But it gives me the error:
Unable to find column with logical name in table A
It appears that the "name" property of the column it has to find is blank someway.
Need some help please!
Please have a look at Official Java EE 6 Tutorial about composite primary key. You can use #EmbeddedId #Embeddable and/or #IdClass annotations.
For example
// File: APK.java ---------------------
#Embeddable
public class APK implements Serializable {
public Integer idShared;
public String nKey;
}
// File: A.java ---------------------
#Entity
public class A {
#EmbeddedId public APK id;
}