Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
Bug 319276 - history does not work with bi-directional 1-1 mappings
Summary: history does not work with bi-directional 1-1 mappings
Status: CLOSED FIXED
Alias: None
Product: z_Archived
Classification: Eclipse Foundation
Component: Eclipselink (show other bugs)
Version: unspecified   Edit
Hardware: All All
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: David Minsky CLA
QA Contact: Project Inbox CLA
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2010-07-08 10:38 EDT by john.vandale CLA
Modified: 2022-06-09 10:02 EDT (History)
3 users (show)

See Also:


Attachments
fix and test case (8.23 KB, patch)
2010-07-13 20:29 EDT, john.vandale CLA
no flags Details | Diff
fix and test (8.23 KB, patch)
2010-07-14 18:44 EDT, john.vandale CLA
no flags Details | Diff
fix and test (10.00 KB, patch)
2010-07-19 12:14 EDT, john.vandale CLA
david.minsky: iplog+
Details | Diff
in the test throw warning if its MySQL (954 bytes, patch)
2010-07-23 11:42 EDT, john.vandale CLA
david.minsky: iplog+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description john.vandale CLA 2010-07-08 10:38:11 EDT
Build Identifier: 

Our history support does not work with bi-directional 1-1s.  When we perform
the update after the shallow insert we do not include the correct values in
the row.  This issue is that it is an insert query, but actually did an
update in the main table and the history policy was expecting an insert row.
Also the logical delete is not done and needs to be otherwise there will be
two active rows.

>>> from forums
Hi All,

I have a HistoryPolicy set up in my "User" descriptor as follows:
HistoryPolicy policy = new HistoryPolicy();
policy.addHistoryTableName("USER", "USER_HIST");
policy.addStartFieldName("ROW_EFFECTIVE_AT");
policy.addEndFieldName("ROW_EXPIRES_AT");
setHistoryPolicy(policy);

However, my USER table contains NOT NULL INITIALLY DEFERRED columns for
foreign key (FK) relationships to other objects. Upon inserting a new User
object, I'm seeing a corresponding insert into the history table with the
relationship FKs set to null (as expected). Then when TopLink circles around
and updates the User object with the FKs from the newly inserted, related
objects, I'm seeing another insert into the history table. Only this time,
only the FKs are being inserted, which causes contraint violations on other
columns within the history table. FWIW, This is all within a single
transaction.

What am I missing? What do I need to do to get the History Policy to do an
update instead of the secondary insert? Or... other suggestions are welcomed.

USER table is:
create table USER
(
OID NUMBER(10,0) NOT NULL,
CREATED_AT TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(80) NOT NULL,
UPDATED_AT TIMESTAMP NOT NULL,
UPDATED_BY VARCHAR2(80) NOT NULL,
IS_DELETED CHAR(1) NOT NULL,
AUDIT_HISTORY_OID NUMBER(10,0) NULL,
USER_ID VARCHAR2(50) NOT NULL,
PASSWORD VARCHAR2(50) NULL,
EMPLOYEE_ID VARCHAR2(50) NULL,
FIRST_NAME VARCHAR2(50) NULL,
MIDDLE_NAME VARCHAR2(50) NULL,
LAST_NAME VARCHAR2(50) NULL,
IS_ACTIVE CHAR(1) NULL,
SERVICE_DATE DATE NULL,
BIRTH_DATE DATE NULL,
SSN_LAST_FOUR VARCHAR2(4) NULL,
TYPE_INDICATOR VARCHAR2(80) NOT NULL INITIALLY DEFERRED,
ORGANIZATION_UNIT_OID NUMBER(10,0) NULL,
USER_PREFERENCES_OID NUMBER(10,0) NULL,
constraint USER_PK PRIMARY KEY (OID)
);

HISTORY table is:
create table USER_HIST
(
OID NUMBER(10,0) NOT NULL INITIALLY DEFERRED,
CREATED_AT TIMESTAMP NOT NULL,
CREATED_BY VARCHAR2(80) NOT NULL,
UPDATED_AT TIMESTAMP NOT NULL,
UPDATED_BY VARCHAR2(80) NOT NULL,
IS_DELETED CHAR(1) NOT NULL,
AUDIT_HISTORY_OID NUMBER(10,0) NULL,
USER_ID VARCHAR2(50) NOT NULL,
PASSWORD VARCHAR2(50) NULL,
EMPLOYEE_ID VARCHAR2(50) NULL,
FIRST_NAME VARCHAR2(50) NULL,
MIDDLE_NAME VARCHAR2(50) NULL,
LAST_NAME VARCHAR2(50) NULL,
IS_ACTIVE CHAR(1) NULL,
SERVICE_DATE DATE NULL,
BIRTH_DATE DATE NULL,
SSN_LAST_FOUR VARCHAR2(4) NULL,
TYPE_INDICATOR VARCHAR2(80) NOT NULL INITIALLY DEFERRED,
ORGANIZATION_UNIT_OID NUMBER(10,0) NULL,
USER_PREFERENCES_OID NUMBER(10,0) NULL,
ROW_EFFECTIVE_AT TIMESTAMP NOT NULL,
ROW_EXPIRES_AT TIMESTAMP NULL,
constraint USER_HIST_PK PRIMARY KEY (OID, ROW_EFFECTIVE_AT)
);

Output is as follows:
INSERT INTO USER (OID, BIRTH_DATE, SSN_LAST_FOUR, PASSWORD, IS_DELETED,
CREATED_BY, IS_ACTIVE, CREATED_AT, SERVICE_DATE, UPDATED_BY, USER_ID,
EMPLOYEE_ID, UPDATED_AT, ORGANIZATION_UNIT_OID, USER_PREFERENCES_OID,
AUDIT_HISTORY_OID, MIDDLE_NAME, FIRST_NAME, LAST_NAME, TYPE_INDICATOR) VALUES
(51, {ts '1985-08-10 16:44:20.488'}, '2345', 'unencryptedPassword', 'N',
'pst', 'Y', {ts '2007-08-10 16:44:30.715'}, {ts '2005-08-10 16:44:20.489'},
'pst', 'empM', 'empM', {ts '2007-08-10 16:44:30.715'}, NULL, NULL, NULL,
'fakeMiddle', 'fakeFirst', 'fakeLast', 'Employee')

INSERT INTO USER_HIST (OID, BIRTH_DATE, SSN_LAST_FOUR, PASSWORD, IS_DELETED,
CREATED_BY, IS_ACTIVE, CREATED_AT, SERVICE_DATE, UPDATED_BY, USER_ID,
EMPLOYEE_ID, UPDATED_AT, ORGANIZATION_UNIT_OID, USER_PREFERENCES_OID,
AUDIT_HISTORY_OID, MIDDLE_NAME, FIRST_NAME, LAST_NAME, TYPE_INDICATOR,
ROW_EFFECTIVE_AT) VALUES (51, {ts '1985-08-10 16:44:20.488'}, '2345',
'unencryptedPassword', 'N', 'pst', 'Y', {ts '2007-08-10 16:44:30.715'}, {ts
'2005-08-10 16:44:20.489'}, 'pst', 'empM', 'empM', {ts '2007-08-10
16:44:30.715'}, NULL, NULL, NULL, 'fakeMiddle', 'fakeFirst', 'fakeLast',
'Employee', {ts '2007-08-10 16:44:30.719'})

INSERT INTO AUDIT_HISTORY (OID, OWNING_AUDITABLE_OBJECT_OID, TYPE_INDICATOR)
VALUES (96, 51, 'Employee')

UPDATE USER SET AUDIT_HISTORY_OID = 96, LAST_NAME = 'fakeLast', MIDDLE_NAME =
'fakeMiddle', FIRST_NAME = 'fakeFirst', CREATED_AT = {ts '2007-08-10
16:44:30.715'}, CREATED_BY = 'pst', SERVICE_DATE = {ts '2005-08-10
16:44:20.489'}, EMPLOYEE_ID = 'empM', PASSWORD = 'unencryptedPassword',
USER_ID = 'empM', UPDATED_AT = {ts '2007-08-10 16:44:30.715'}, IS_ACTIVE =
'Y', USER_PREFERENCES_OID = 51, BIRTH_DATE = {ts '1985-08-10 16:44:20.488'},
SSN_LAST_FOUR = '2345', UPDATED_BY = 'pst' WHERE (OID = 51)

INSERT INTO USER_HIST (AUDIT_HISTORY_OID, LAST_NAME, MIDDLE_NAME, FIRST_NAME,
CREATED_AT, CREATED_BY, SERVICE_DATE, EMPLOYEE_ID, PASSWORD, USER_ID,
UPDATED_AT, IS_ACTIVE, USER_PREFERENCES_OID, BIRTH_DATE, SSN_LAST_FOUR,
UPDATED_BY, ROW_EFFECTIVE_AT) VALUES (96, 'fakeLast', 'fakeMiddle',
'fakeFirst', {ts '2007-08-10 16:44:30.715'}, 'pst', {ts '2005-08-10
16:44:20.489'}, 'empM', 'unencryptedPassword', 'empM', {ts '2007-08-10
16:44:30.715'}, 'Y', 51, {ts '1985-08-10 16:44:20.488'}, '2345', 'pst', {ts
'2007-08-10 16:44:30.752'})

Internal Exception: java.sql.SQLException: ORA-01400: cannot insert NULL into
("MBA_DEV"."USER_HIST"."OID")
[java] Error Code: 1400

Reproducible: Always

Steps to Reproduce:
1. Setup a project with entities that have a bi-directional 1 - 1 relationship and a history policy established.

2. In a UOW instantiate, register and commit new objects initialized with this relationship.  For example BABY has a FK that is the BABY_MONITOR PK. BABY_MONITOR has a FK that is the BABY PK.  Both have a history policy defined:

        UnitOfWork uow = dbSession.acquireUnitOfWork();
        Baby baby = new Baby();
        baby.setId(new BigDecimal(1056));
        baby.setName("Foo");
        BabyMonitor monitor = new BabyMonitor();
        monitor.setId(new BigDecimal(1156));
        baby.setBabyMonitor(monitor);
        monitor.setBaby(baby);
        uow.registerObject(baby);
        uow.commit();

3.  If the UoW is acquired from a non-historical session this executes successfully.  If its acquired from a historical session it results in the java.sql.SQLException: ORA-01400: cannot insert NULL ... from an attempt to INSERT a null PK into BABY_MONITOR_HIST.
Comment 1 john.vandale CLA 2010-07-13 20:29:44 EDT
Created attachment 174244 [details]
fix and test case
Comment 2 john.vandale CLA 2010-07-14 18:44:16 EDT
Created attachment 174359 [details]
fix and test

changed a comment to reflect correct bug number
Comment 3 john.vandale CLA 2010-07-19 12:14:19 EDT
Created attachment 174644 [details]
fix and test

performance improvement - only increment the timestamp if a shallow commit
Comment 4 David Minsky CLA 2010-07-20 14:16:57 EDT
Fixed in revision 7880
Comment 5 john.vandale CLA 2010-07-23 11:42:06 EDT
Created attachment 175079 [details]
in the test throw warning if its MySQL
Comment 6 David Minsky CLA 2010-07-23 13:16:05 EDT
Updated changes to testing checked in - r7912
Comment 7 Eclipse Webmaster CLA 2022-06-09 10:02:25 EDT
The Eclipselink project has moved to Github: https://github.com/eclipse-ee4j/eclipselink