olingo jpa processor v4 Exception when using #ManyToOne relation.
com.sap.olingo.jpa.metadata.core.edm.mapper.exception.ODataJPAModelException: Error when creating Referential Constraints for 'content': Property for 'content_id' not found at 'Repository'
#ManyToOne(optional = true)
#JoinColumn(name = "content_id", insertable = false, updatable = false)
public Repository getContent() {
return content;
}
#ManyToOne
#JoinColumn(name = "space_id", insertable = false, updatable = false)
public Space getSpace() {
return space;
}
I think you need to use refencedColumnName.
refencedColumnName is there to specify another column as the id column of the other table.
#ManyToOne(optional = true)
#JoinColumn(name = "content_id",referencedColumnName="here the id of repository",insertable = false, updatable= false)
Related
Following situation:
An root-Entity is build up from two database tables.
#Table("A")
#SecondaryTable(name="B", pkJoinColumns = {
#PrimaryKeyJoinColumn(name = "key1", referencedColumnName = "key1"),
#PrimaryKeyJoinColumn(name = "key2", referencedColumnName = "key2")})
The root entity contains an one-to-one association to an other entity lets call it "sub"
#OneToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name = "key1", referencedColumnName = "key1", updatable = false, insertable = false),
#JoinColumn(name = "KVSTU", referencedColumnName = "KVSTUFE", updatable = false, insertable = false),
#JoinColumn(name = "CODE_TARF_GEN", referencedColumnName = "TARIFGENERATION", updatable = false,
insertable = false)
})
private Sub sub;
Every thing works fine, but the JPA provider (in my case EclipseLink) doen't create an (outer) join. Instead of a join, for every dependend sub-entity an extra query is created.
I also tried pk join columns instead of join columns for the one-to-one association, with the same result.
What am I doing wrong?
can some one help me to map this 3 entities correctly, because i have tried many solution but not working.
i have this 3 entities :
Product,Item and Pack that should be mapped like this:
Product entity
public class Product implements Serializable {
#OneToMany(mappedBy="parentProduct", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
#PrimaryKeyJoinColumn
private List<Pack> packListParent;
#OneToMany(mappedBy="childProduct", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
#PrimaryKeyJoinColumn
private List<Pack> packListChild;
}
Pack entity
public class Pack implements Serializable {
#EmbeddedId
protected PackPK PackPK;
#MapsId("itemId")
#JoinColumn(name = "item_id", referencedColumnName = "item_id", insertable = true, updatable = true)
#ManyToOne(fetch = FetchType.LAZY)
private Item item;
#MapsId("parentProductId")
#JoinColumn(name = "product_id", referencedColumnName = "product_id", insertable = true, updatable = true)
#ManyToOne(fetch = FetchType.LAZY)
private Product parentProduct;
#MapsId("childProductId")
#JoinColumn(name = "child_product_id", referencedColumnName = "product_id", insertable = true, updatable = true)
#ManyToOne(fetch = FetchType.LAZY)
private Product childProduct;
}
#Embeddable
public class PackPK implements Serializable {
#Basic(optional = false)
#Column(name = "product_id")
private Long parentProductId;
#Basic(optional = false)
#Column(name = "item_id")
private Long itemId;
#Basic(optional = false)
#Column(name = "child_product_id")
private Long childProductId;
}
Item entity
public class Item implements Serializable {
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
#PrimaryKeyJoinColumn
private List<Pack> PackList;
}
this mapping work in eclipselink but when i have migrated to spring data jpa with eclipselink i have this warning when i launch the server application.
This is the error message :
WARN - [AnnotationConfigServletWebServerApplicationContext]
Exception encountered during context initialization - cancelling refresh attempt:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'produitService': Unsatisfied dependency expressed through field 'PackService';
nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'PackService': Invocation of init method failed;
nested exception is java.lang.IllegalArgumentException: Expected id attribute type [class com.project.jpa.domain.PackPK]
on the existing id attribute [SingularAttributeImpl[EntityTypeImpl#1851998201:Item
[ javaType: class com.project.jpa.domain.Item descriptor: RelationalDescriptor(com.project.jpa.domain.Item --> [DatabaseTable(item)]), mappings: 47],
org.eclipse.persistence.mappings.ManyToOneMapping[item]]] on the identifiable type [EntityTypeImpl#1341697553:Pack [ javaType: class com.project.jpa.domain.Pack descriptor:
RelationalDescriptor(com.project.jpa.domain.Pack --> [DatabaseTable(pack_svod_content)]), mappings: 6]] but found attribute type [class com.project.jpa.domain.Item].
I'm Using JPA 2.1. I have 3 entities: Dr01 , Dr02 and Dr03 with the following structure:
public class Dr01 implements Serializable {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "dr01")
private List<Dr02> dr02List;
}
public class Dr02 implements Serializable {
#OneToMany(cascade = CascadeType.ALL, mappedBy = "dr02")
private List<Dr03> dr03List;
#JoinColumn(name = "DR2CLM", referencedColumnName = "DR1CLM", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Dr01 dr01;
}
public class Dr03 implements Serializable {
#JoinColumns({
#JoinColumn(name = "DR3CLM", referencedColumnName = "DR2CLM", insertable = false, updatable = false),
#JoinColumn(name = "DR3PTFN", referencedColumnName = "DR2PTFN", insertable = false, updatable = false)})
#ManyToOne(optional = false)
private Dr02 dr02;
private elementOBJ element;
}
public class elementOBJ implements Serializable {
#Column(name = "XXX")
private int id;
#Column(name = "YYY")
private int status;
}
I want to select from Dr01 and get only the Dr03 objects that have element objects which contains a value of 1 inside the status field.
How do I retrieve dr03List filtered by it's status value? (filtered not after the select).
Thank's In Advance.
Options that may be of assistance:
Create a DB view based on status of DR03 table and map your
entity to that.
Use JPA Inheritance using status as a
DiscriminatorColumn.
If using Hibernate use the non-JPA #Where
annotation to filter the collection
I need help to understand how ORM works. Here is the scenario that is very common. I have two main tables Organization and RelatedParty which have to be in many to many relation. But there is also relation_type attribute that defines what kind of relation exists between Organization and Relatedparty.
Here are my entity classes:
Organization:
#Entity
#Table(name = "organization", catalog = "...", schema = "")
#XmlRootElement
public class Organization implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "organization_id", nullable = false)
private Integer organizationId;
#Column(name = "organization_name", nullable = false)
private String organizationName;
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "organization")
private List<Organdrelatedparty> organdrelatedpartyList;
...
//getter setter methods
Organdrelatedparty: which uses composite primary key OrgandrelatedpartyPK
#Entity
#Table(name = "organdrelatedparty", catalog = "...", schema = "")
#XmlRootElement
public class Organdrelatedparty implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected OrgandrelatedpartyPK organdrelatedpartyPK;
#JoinColumn(name = "relatedParty_id", referencedColumnName = "relatedParty_id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false, cascade= {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
private Relatedparty relatedparty;
#JoinColumn(name = "orgRelation_id", referencedColumnName = "orgRelation_id", nullable = false)
#ManyToOne(optional = false)
private ParOrgrelationtype orgRelationid;
#JoinColumn(name = "organization_id", referencedColumnName = "organization_id", nullable = false, insertable = false, updatable = false)
#ManyToOne(optional = false)
private Organization organization;
...
//getter setter methods
OrgandrelatedpartyPK
#Embeddable
public class OrgandrelatedpartyPK implements Serializable {
#Basic(optional = false)
#NotNull
#Column(name = "relatedParty_id", nullable = false)
private int relatedPartyid;
#Basic(optional = false)
#NotNull
#Column(name = "organization_id", nullable = false)
private int organizationId;
...
//getter setter methods
RelatedParty: which is in unidirectional oneToMany relationship with organdRelatedParty class. In other word that relatedParty entity has no knowledge about organdRelatedParty entity that is on the other side.
#Entity
#Table(name = "relatedparty", catalog = "...", schema = "")
#XmlRootElement
public class Relatedparty implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "relatedParty_id", nullable = false)
private Integer relatedPartyid;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 100)
#Column(name = "firstName", nullable = false, length = 100)
private String firstName;
#Size(max = 100)
#Column(name = "lastName", length = 100)
private String lastName;
#Basic(optional = false)
#NotNull
#Column(name = "isForeign", nullable = false)
private boolean isForeign;
...
//getter setter methods
For insertion, if I persist new Organization Entity, it cascades persist activity to new OrgandrelatedParty which also cascades persist activity to new RelatedParty. So all the related entities are persisted and it works fine.
For updating, User is expected to change existing organization and relatedParty entities and also add new relatedParty to organization. So we prefer to delete all OrgandrelatedParties first and add new relatedParties and edited relatedParties again after that.
This is our method that handles updating: We pass new organization and also all new and old relatedParties as a list to method:
firs we delete all old OrgAndRelatedParties then we create again all relatedParties in list as new OrgandrelatedParties. This is main method to update organization.
public void updateOrganization(Organization newOrganization, List<Relatedparty> newShareList) throws ControlException {
try{
tx.begin();
this.updateOrgAndRelatedShares(newOrganization, newShareList);
customerController.updateOrganization(newOrganization);
tx.commit();
}catch(ControlException ex){
...
customerController's updateOrganization method does first find old Organization by find method of entity manager then copies all attributes of new organization to old then merges old organization and flush:
public void updateOrganization(Organization newOrganization)
{
Organization preOrganization = em.find(Organization.class, newOrganization.getOrganizationId);
preOrganization.setOrganizationId(newOrganization.getOrganizationId);
preOrganization.setOrganizationName(newOrganization.getOrganizationName);
em.merge(preOrganization);
em.flush();
}
here are other methods:
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void updateOrgAndRelatedShares(Organization org, List<Relatedparty> shareList) throws ControlException
{
for(Iterator<Organdrelatedparty> it = org.getOrgandrelatedpartyList().iterator(); it.hasNext();)
{
Organdrelatedparty op = it.next();
it.remove();
op.setOrganization(null);
op.setRelatedparty(null);
deleteOrgRelated(op);
}
org.getOrgandrelatedpartyList().clear();
for(Relatedparty relatedParty: shareList){
int parOrgRelationTypeId = relatedParty.getIsPerson() ? 1:2;
createOrgAndRelatedParty(org, relatedParty, parOrgRelationTypeId);
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteOrgRelated(Organdrelatedparty org) throws ControlException{
try{
org = em.find(Organdrelatedparty.class, org.getOrgandrelatedpartyPK());
em.remove(org);
em.flush();
}
catch(Exception ex){
Logger.getLogger(RelatedpartyController.class.getName()).log(Level.SEVERE, null, ex);
throw new ControlException("Couln't delete org relation", ex);
}
}
#TransactionAttribute(TransactionAttributeType.REQUIRED)
private void createOrgAndRelatedParty(Organization org, Relatedparty relatedParty, int parOrgRelationTypeId) throws ControlException{
if(findRelatedPartyByRegNum(relatedParty.getRegisterNumber()) == null || relatedParty.getRelatedPartyid() == null){
createRelated(relatedParty);
}else{
relatedParty = updateRelatedParty(relatedParty);
}
Organdrelatedparty preOrp = new Organdrelatedparty(relatedParty.getRelatedPartyid(),
preOrp.setOrganization(org);
preOrp.setRelatedparty(relatedParty);
preOrp.setOrgRelationid(prepareOrgandRelatedPartyType(parOrgRelationTypeId));
org.getOrgandrelatedpartyList().add(preOrp);
}
And my question is when I merge organization entity with new List organdrelatedpartyList
it throws exception like this:
SEVERE: java.lang.IllegalArgumentException: Cannot merge an entity that has been removed: mn.bsoft.crasmonclient.model.Organdrelatedparty[ organdrelatedpartyPK=mn.bsoft.crasmonclient.model.OrgandrelatedpartyPK[ relatedPartyid=71, organizationId=19 ] ]
I found out that eclipseLink does persist operation first then remove operations. So I think that it tries to insert organdrelatedparty entity that has same composite id with entity which was not deleted previously from database. I flushes every time I remove old organdrelatedparties. But it doesn't help. What is the solution? Any idea guys.
I'm using jpa 2.0; eclipseLink as provider and glassfish 3.1.2
You seem to be making these a lot more complicated than they need to be.
Why don't you just remove the Organdrelatedparty that have been removed, instead of deleting all of them, then reincarnating some of them? Reincarnating objects, especially in the same transaction is normally a bad idea.
The error that is occurring is on merge() according to the code you included you are only call merge in updateOrgAndRelatedShares(), so I don't see how this object is removed at this point? Or is your code different than you show, please include the exception stack.
You updateOrganization() method is bad, it updates the objects Id, which you should never do. Also it calls merge for no reason, it already changed the object.
Also I would normally recommend using an IdClass instead of an EmbeddedId, and recommend using TABLE or SEQUENCE id generation instead if IDENTITY.
I have #OneToMAny realationship inside my entity.
Is it possible to disable jpa from generating select for the joined column? beacuse I have many records in my main table and when selecting them , each record performs select for the joined column. I would like to disable this select is that possible?
UPDATE:
I tried inserting fetch LAZY but it still creates a select for Table02f and Table03f...
This is my code:
public class Table01f implements Serializable {
#OneToMany(fetch=FetchType.LAZY , cascade = CascadeType.ALL, mappedBy = "table01f")
private List<Table02f> table02fList;
//getter & setter...
}
public class Table02f implements Serializable {
#JoinColumn(name = "F2PRP", referencedColumnName = "F1PRP", insertable = false, updatable = false)
#ManyToOne(optional = false)
#JsonIgnore
private Table01f table01f;
#OneToMany(fetch=FetchType.LAZY , cascade = CascadeType.ALL, mappedBy = "table02f")
private List<Table03f> table03fList;
//getter & setter...
}
public class Table03f implements Serializable {
#JoinColumns({
#JoinColumn(name = "F3PRP", referencedColumnName = "F2PRP", insertable = false, updatable = false),
#JoinColumn(name = "F3BRN", referencedColumnName = "F2BRN", insertable = false, updatable = false)})
#ManyToOne(optional = false)
#JsonIgnore
private Table02f table02f;
//getter & setter...
}
Thank's In Advance.
Just add the fetch type LAZY to your #OneToMany relationship:
#OneToMany(fetch=FetchType.LAZY)
When you load the list of your main entities, JPA won't populate your list for this relationship, avoiding the generation of the SELECT.
Just have a look at this functionality in JPA documentation so that you can understand how to use it.
If you don't need the data make it LAZY (in general always make everything LAZY).
If you need the data, then you can use batch fetching, or join fetching.
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html