how to make openjpa 2.2.0 not persist foreign key - persistence

I have two tables..
Asset table
ASSET_ID SYSIBM INTEGER 4 0 No
USER_ID SYSIBM INTEGER 4 0 No
ASSET_TYPE_ID SYSIBM SMALLINT 2 0 No
ACCESSIBILITY_ID SYSIBM SMALLINT 2 0 Yes
DOWNLOAD_TYPE_ID SYSIBM SMALLINT 2 0 No
ASSET_STATUS_ID SYSIBM SMALLINT 2 0 No
ASSET_MARKETING_ID SYSIBM SMALLINT 2 0 Yes
ASSET_PI_SPI_ID SYSIBM SMALLINT 2 0 Yes
and the Accesibility table
ACCESSIBILITY_ID SYSIBM SMALLINT 2 0 No
ACCESSIBILITY_DESC SYSIBM VARCHAR 50 0 No
i have two beans,
Asset Bean
#Column(name="ASSET_ID")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int assetId;
#Column(name="DATE_CREATED")
private Timestamp dateCreated;
#Column(name="LAST_UPDATED")
private Timestamp lastUpdated;
#Column(name="DATE_PUBLISHED")
private Timestamp datePublished;
#Column(name="ASSET_SURVEY")
private Short assetSurvey;
#Column(name="ASSET_HELP")
private Short assetHelp;
#Column(name="ACCEPTED_TERMS")
private Short acceptedTerms;
#Column(name="ASSET_DESC")
#Lob
private String assetDesc;
#Column(name="ASSET_ALIAS")
private String assetAlias;
#Column(name="ASSET_TITLE")
private String assetTitle;
#Column(name="ASSET_SUMMARY")
private String assetSummary;
#Column(name="ASSET_URL")
private String assetUrl;
#Column(name="ASSET_ORIGINALITY")
private Short assetOriginality;
#Column(name="ASSET_INVENTION")
private Short invationDisclosure;
#Column(name="ASSET_PRIVACY")
private String privacyCompliance;
#ManyToOne
#JoinColumn(name="ASSET_PI_SPI_ID")
private AssetPiSpi assetPiSpiId;
#ManyToOne
#JoinColumn(name="ASSET_MARKETING_ID")
#ForeignKey
private AssetMarketing assetMarketingId;
#ManyToOne(cascade=CascadeType.REMOVE,fetch=FetchType.LAZY)
#JoinColumn(name="ACCESSIBILITY_ID")
#ForeignKey
private Accessibility accessibilityId;
and Accessibility
#Column(name="ACCESSIBILITY_ID")
private short accessibilityId;
#Column(name="ACCESSIBILITY_DESC")
private String accessibilityDesc;
#OneToMany(mappedBy="accessibilityId",cascade=CascadeType.REMOVE,fetch=FetchType.LAZY)
private Set<Asset> assetCollection;
when the EntitiManager.flush() get's called in my ManagerBean
em.persist(asset);
em.flush();
I am getting
javax.ejb.EJBException: See nested exception; nested exception is: org.apache.openjpa.persistence.InvalidStateException: Encountered unmanaged object "com.ibm.tap.ejb.dao.entity.Accessibility#169e3455" in life cycle state unmanaged while cascading persistence via field "com.ibm.tap.ejb.dao.entity.Asset.accessibilityId" during flush. However, this field does not allow cascade persist. You cannot flush unmanaged objects or graphs that have persistent associations to unmanaged objects. Suggested actions: a) Set the cascade attribute for this field to CascadeType.PERSIST or CascadeType.ALL (JPA annotations) or "persist" or "all" (JPA orm.xml), b) enable cascade-persist globally, c) manually persist the related field value prior to flushing. d) if the reference belongs to another context, allow reference to it by setting StoreContext.setAllowReferenceToSiblingContext(). FailedObject: com.ibm.tap.ejb.dao.entity.Accessibility#169e3455
i have tried changing the Asset class to
#ManyToOne(cascade=CascadeType.PERSIST,fetch=FetchType.LAZY)
#JoinColumn(name="ACCESSIBILITY_ID")
#ForeignKey
private Accessibility accessibilityId;
When i do that i get
javax.ejb.EJBException: See nested exception; nested exception is: org.apache.openjpa.persistence.EntityExistsException: An object of type "com.ibm.tap.ejb.dao.entity.Accessibility" with oid "1" already exists in this context; another cannot be persisted. FailedObject: com.ibm.tap.ejb.dao.entity.Accessibility#166c27b9
Which make sense to me that i am trying to persist the table i already have. What am i doing wrong?

The issue you are having isn't caused by foreign keys. What is happening is that your Asset object contains an Accessibility object that is not being managed by OpenJPA. How to fix this depends on the state of the Accessibility record:
Does the Accessibility record already exist in the database? If so, load it using getEntityManager.find(Accessibility.class, uid) first, and then set it onto your Asset object before you try to persist the Asset object.
If the Accessibility record hasn't already been persisted, then need to persist it first using "getEntityManager.persist(accessibility)" and then set it onto your Asset object before you try to persist it. Or, your other option is to change the cascade type for your accessibility collection to allow persisting, as follows:
#ManyToOne(cascade=cascade={ CascadeType.PERSIST, CascadeType.REMOVE },fetch=FetchType.LAZY)
#JoinColumn(name="ACCESSIBILITY_ID")
#ForeignKey
private Accessibility accessibilityId;
If you make the cacade change, then any unpersisted Accessibility object on your Asset object will be persisted automatically when you persist the Asset object.

Related

Why does JPA call sql update on delete?

Let´s assume these two entities:
#Entity
public class MyEntity {
#Id private String id;
#OneToMany(mappedBy = "myEntity", cascade = ALL) private Set<MyEntityPredecessor> predecessors;
}
#Entity
public class MyEntityPredecessor{
#Id private String id;
#ManyToOne(name = "entityID", nullable = false) private MyEntity myEntity;
#ManyToOne(name = "entityPre", nullable = false) private MyEntity predecessor;
}
When I try to call a delete with Spring Boot Data (JPA) with a MyEntity Instance, it will work some times (I see the select and then the delete statements in correct order), but sometimes it will try to run an update on the second entity trying to set the "entityPre" Field to null (even thoug it is set to nullable=falsE), causing the DB to send an error (null not allowed!! from DB constraint).
Strangely, this will happen at "random" calls to the delete...
I just call "myEntityRepository.getOne(id)", and then myEntityRepository.delete() with the result... There is no data difference in the DB between calls, the data structure has no null values when calling the delete method, so that should not be the reason.
Why is JPA sometimes trying to call updates on the Predecessor Table, and sometimes directly deleting the values? Am I missing something?
Add a similar ManyToOne annotated set to MyEntity which refers to the other non-nullable property, like:
#OneToMany(mappedBy = "predecessor", cascade = ALL) private Set<MyEntityPredecessor> other;
some explanation:
The issue doesn't happen randomly, but happen when you try to delete an entity which is linked to one (or more) MyEntityPredecessor via the predecessor property (which is mapped to the entityPre field)
Only the other field (entityID) is mapped back to the MyEntity object, so the deletion-cascade only happens via by that field.

Postgres insert record with Sequence generates error - org.postgresql.util.PSQLException: ERROR: relation "dual" does not exist

I am new to Postgres database.
I have a Java Entity class with the below column for ID:
#Entity
#Table(name = "THE_RULES")
public class TheRulesEntity {
/** The id. */
#Column(name = "TEST_NO", precision = 8)
#SequenceGenerator(name = "test_no_seq", sequenceName = "TEST_NO_SEQ")
#GeneratedValue(generator = "test_no_seq", strategy = GenerationType.AUTO)
#Id
private Long id;
/** The test val. */
#Column(name = "TEST_VAL", nullable = false, length = 3)
private String testVal;
Code:
rulesRepository.saveAndFlush(theRulesEntity)
Table:
CREATE TABLE THE_RULES
(
TEST_NO INT NOT NULL,
TEST_VAL VARCHAR(3) NOT NULL
)
CREATE SEQUENCE "TEST_NO_SEQ" START WITH 1000 INCREMENT BY 1;
When I try to insert a new record into the postgres database from my application (the ID value is null in Java code during Debug mode), then I get the below error:
Caused by: org.postgresql.util.PSQLException: ERROR: relation "dual" does not exist
But If I insert the record manually into database table and then update the record from my application, then the record is updated successfully (Probably because the application uses the same ID value so no need to refer to the Sequence TEST_NO_SEQ value anymore)
Looks like the database is not able to access the sequence from dual table.
Could anyone help me how to fix this?
Thanks.
Thanks to Joop and a_horse_with_no_name, the issue is resolved
I have used Oracle driver which is wrong. I have updated my code to use Postgres driver
I created the Sequence again in the database with same name but without the Quotes
I used all capital-case letters in my Java entity class to refer to the sequence correctly

JPA and Postgres sequence pre-allocation size setup incorrectly

I am not able to perist any Entity because of a problem with sequence. I use Glssfish 4, Postgres 9.3 + JPA + EJB3 and Netbeans 8.
Below the excpeption:
Finest: persist() operation called on: MyUser{id=null, email=a#e.it, password=test, firstname=test, lastname=test, company=Test}.
Finest: Execute query ValueReadQuery(sql="select nextval('mom_seq_id')")
Finest: Connection acquired from connection pool [read].
Finest: reconnecting to external connection pool
Fine: select nextval(mom_seq_id)
Finest: Connection released to connection pool [read].
Warning: Local Exception Stack:
Exception [EclipseLink-7027] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The sequence named [mom_seq_id] is setup incorrectly. Its increment does not match its pre-allocation size.
at org.eclipse.persistence.exceptions.ValidationException.sequenceSetupIncorrectly(ValidationException.java:1604)
at org.eclipse.persistence.sequencing.StandardSequence.createVector(StandardSequence.java:96)
...
The sequence on Postgres:
CREATE SEQUENCE my_seq_id
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 27
CACHE 1;
ALTER TABLE my_seq_id
OWNER TO postgres;
COMMENT ON SEQUENCE my_seq_id
IS 'Sequence for autoincrement id on MyClass';
And an extract of my Entity:
#Entity
#Table(name = "myuser")
#XmlRootElement
public class MyUser implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name="MYSEQ",
sequenceName="my_seq_id")
#GeneratedValue(strategy = GenerationType.SEQUENCE,
generator="MYSEQ")
#Basic(optional = false)
#Column(name = "id")
private Integer id;
Can anyone explain what is wrong?
Thanks
I resolved my issue but I don't know why! I saw that the default value of allocationSize() is 50:
package javax.persistence;
#Target(value = {ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(value = RetentionPolicy.RUNTIME)
public #interface SequenceGenerator {
public String name();
public String sequenceName() default "";
public String catalog() default "";
public String schema() default "";
public int initialValue() default 1;
public int allocationSize() default 50;
}
And I have updated my Postgres sequence increment_by value from 1 to 50 and now it works!
For reasons beyond my understanding, the JPA spec picked 50 as the default increment for a sequence generator.
PostgreSQL defaults to 1.
If the two don't match, things get ugly, because JPA thinks it can use values that someone else also thinks they have assigned. At least EclipseLink detects this; Hibernate just goes on merrily trying to re-use already assigned keys.
If your sequence is:
CREATE SEQUENCE my_seq_id
INCREMENT 1
then your mapping must reflect that:
#SequenceGenerator(name="MYSEQ",
sequenceName="my_seq_id", allocationSize=1)
I strongly suggest being explicit about the increment, even if you leave it at the default of 50 and alter the PostgreSQL sequence instead. It'll save your and others' sanity when debugging later.
Changing the value of INCREMENT from 1 to 50 into my Postgres sequence resolved the issue. As suggested by #unwichtich it is a good idea to specify allocationSize=50 attribute through the #SequenceGenerator annotation.

Entity bean 3.0 composite key issue

1: I have a table as shown below :
Name Null? Type
ATX_ID NOT NULL NUMBER(16)
ATX_GLM_CD NOT NULL NUMBER(5)
ATX_CRDR_FLG NOT NULL VARCHAR2(1)
ATX_AMT NOT NULL NUMBER(15,2)
ATX_STTS NOT NULL VARCHAR2(1)
ATX_TCM_ID NOT NULL NUMBER(16)
ATX_TXN_DT NOT NULL DATE
ATX_CRTE_BY NOT NULL VARCHAR2(30)
ATX_CRTE_DT NOT NULL DATE
The columns ATX_ID,ATX_GLM_CD and ATX_CRDR_FLG form a composite primary key.
2: I have created an entity bean class for the above table as follows :
#Entity
public class AcctngTxns implements Serializable {
private BigDecimal atxAmt;
private String atxStts;
private BigDecimal atxTcmId;
private Date atxTxnDt;
private String atxCrteBy;
private Date atxCrteDt;
#EmbeddedId
private AcctngTxnsPK acctngTxnsPK;
public AcctngTxns() {
//super();
}
/*getters and setters*/
}
#Embeddable
public class AcctngTxnsPK implements Serializable {
private long atxId;
private long atxGlmCd;
private String atxCrdrFlg;
private static final long serialVersionUID = 1L;
public AcctngTxnsPK() {
//super();
}
/*necessary overrides*/
}
3: /orm.xml/
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
version="1.0">
4: /persistence.xml/
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
DataSource
com.nseit.ncfm2.data.ejb.entity.AcctngTxns
5: While accessing the entity bean via a session bean,I am getting the following exception :
<[weblogic.servlet.internal.WebAppServletContext#1a1bc8f - appName: '_auto_generated_ear_', name: 'AWebApp', context-path: '/AWebApp', spec-version: '2.5'] Servlet failed with Exception
javax.ejb.EJBException: EJB Exception: ; nested exception is:
org.apache.openjpa.persistence.ArgumentException: Fields "com.nseit.ncfm2.data.ejb.entity.AcctngTxns.acctngTxnsPK" are not a default persistent type, and do not have any annotations indicating their persistence strategy. If you do not want these fields to be persisted, annotate them with #Transient.
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.unwrapRemoteException(RemoteBusinessIntfProxy.java:105)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:87)
at $Proxy127.gottaAccessEntity3(Unknown Source)
at jsp_servlet.__result.jspService(_result.java:115)
at weblogic.servlet.jsp.JspBase.service(JspBase.java:34)
Truncated. see log file for complete stacktrace
org.apache.openjpa.persistence.ArgumentException: Fields "com.nseit.ncfm2.data.ejb.entity.AcctngTxns.acctngTxnsPK" are not a default persistent type, and do not have any annotations indicating their persistence strategy. If you do not want these fields to be persisted, annotate them with #Transient.
at org.apache.openjpa.persistence.PersistenceMetaDataFactory.validateStrategies(PersistenceMetaDataFactory.java:399)
at org.apache.openjpa.persistence.PersistenceMetaDataFactory.load(PersistenceMetaDataFactory.java:205)
at org.apache.openjpa.meta.MetaDataRepository.getMetaDataInternal(MetaDataRepository.java:474)
at org.apache.openjpa.meta.MetaDataRepository.getMetaData(MetaDataRepository.java:294)
at org.apache.openjpa.kernel.BrokerImpl.newObjectId(BrokerImpl.java:1114)
Truncated. see log file for complete stacktrace
7: Certainly,I do not want the primary key fields to be updated.
8: I tried to figure out the implementation of the below points mentioned in JPA documentation :
A composite primary key must be represented and mapped to multiple fields or properties of the entity class, or must be represented and mapped as an embeddable class.
If the class is mapped to multiple fields or properties of the entity class, the names and types of the primary key fields or properties in the primary key class must match those of the entity class.
8: Please help me in resolving the issue.
Thanks !
I found a solution by trial-and-error method. It seems that with JPA 1.0,it is necessary to mention the embedded-id in orm.xml file as follows :
Thanks.

Entity Framework - strange issue with multiple foreign keys mapped to the same table

I am using EF (Framework 3.5 SP1) and have a simple two table demo set up:
Applicants
applicant-id int
applicant-pref-lang-coorepondence int (FK to CodeLanguages)
applicant-pref-lang-exam int (FK to CodeLanguages)
applicant-pref-lang-interview int (FK to CodeLanguages)
CodeLanguages
code-lang-id int
code-lang-desc varchar
A CodeLanguage entry can have 0, 1, * Applicants
Each language ref in Applicants must have 1 (and only one) CodeLanguage ref.
Problem:
When I bring back an Applicant entity (via WCF web service to my WPF-based client), if all three language references (coorespondence, exam, and interview) are all the same, lets say 1000 (english), and then I modify one of them, for example to 1001 (french), then all THREE will be changed to 1001 (french).
Here's the weird part: If all three references are different (lets say coorespondence=english, exam=french, and interview=spanish) and I change one of them - then it behaves as expected and only the one I changed is affected - the others are remain in their original state.
I have spent most of today trying various things such as dropping and recreating associations in the EDMX, recreating the EDMX datamodel - even creating a new database. None of this worked - I'm beginning to thing the issue is with EF and not my code.
Any ideas? Thanks.
An update on the final outcome of this issue. After some very quick and helpful advice from the EF team at Microsoft it was determined that this is expected behaviour from EF 3.5 SP1:
"When you query within the service layer for the Applicant where all languages are the same you end up with two objects, one Applicant with all three navigation properties pointing to the same CodeLanguage object.WCF then re-creates this same graph on the client meaning that the three breakpoints you set are indeed looking at the same property on the same object"
Microsoft provided the basis for my ultimate solution which is this:
First: Create a Partial Class for the Applicants data object and create three properties which reference the three language code_ids:
Partial Public Class Applicants
Private _intPrefCoorespLanguage As Integer = 0
Private _intPrefInterviewLanguage As Integer = 0
Private _intPrefExamLanguage As Integer = 0
<System.Runtime.Serialization.DataMemberAttribute()> _
Public Property MyPrefCoorespLanguageCodeId() As Integer
Get
Return (_intPrefCoorespLanguage)
End Get
Set(ByVal value As Integer)
_intPrefCoorespLanguage = value
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()> _
Public Property MyPrefInterviewLanguageCodeId() As Integer
Get
Return (_intPrefInterviewLanguage)
End Get
Set(ByVal value As Integer)
_intPrefInterviewLanguage = value
End Set
End Property
<System.Runtime.Serialization.DataMemberAttribute()> _
Public Property MyPrefExamLanguageCodeId() As Integer
Get
Return (_intPrefExamLanguage)
End Get
Set(ByVal value As Integer)
_intPrefExamLanguage = value
End Set
End Property
<OnSerializing()> _
Private Sub PopulateClientProperties(ByVal sc As StreamingContext)
Me.MyPrefCoorespLanguageCodeId = Me.PrefCoorespLanguage.code_lang_id
Me.MyPrefInterviewLanguageCodeId = Me.PrefInterviewLanguage.code_lang_id
Me.MyPrefExamLanguageCodeId = Me.PrefExamLanguage.code_lang_id
End Sub
End Class
Second: Recompile and refresh the client's service reference. Use the three language code_id properties to bind to controls in xaml
Third: In the server-side update run the following to update the applciant and its language foreign keys:
myContext = New HR2009Entities
'Get original Applicant and feed in changes from detatched updated Applicant object
Dim OrigApp = (From a In myContext.Applicants Where a.applicant_id = pobjUpdatedApplicant.applicant_id Select a).First
'Apply preferred language foreign key refs
OrigApp.PrefCoorespLanguageReference.EntityKey = _
New EntityKey("HR2009Entities.CodeLanguages", "code_lang_id",pobjUpdatedApplicant.MyPrefCoorespLanguageCodeId)
OrigApp.PrefInterviewLanguageReference.EntityKey = _
New EntityKey("HR2009Entities.CodeLanguages", "code_lang_id", pobjUpdatedApplicant.MyPrefInterviewLanguageCodeId)
OrigApplicant.PrefExamLanguageReference.EntityKey = _
New EntityKey("HR2009Entities.CodeLanguages", "code_lang_id", pobjUpdatedApplicant.MyPrefExamLanguageCodeId)
'Apply Applicant table native-field changes
myContext.ApplyPropertyChanges(OrigApp.EntityKey.EntitySetName, pobjUpdatedApplicant)
'Save to database
myContext.SaveChanges()
myContext.Dispose()
Well you are right this does sound very wierd.
I tried to repro your problem based on what you've explained, but couldn't.
If you have a small repro though I will look into this.
If you want you can email me (alexj) # microsoft.com.
Alex James
Program Manager Entity Framework Team