EJB3: Mapping of 1-to-1 relationships when primary key in the source table is also a foreign key for the target entity
2010-12-25 13:25
676 查看
ThisblogentrywillexplainhowtodefinetheEJB3objectrelationalmappingsforentitiesthathavea1-1associationwhentheprimarykeyoftherelationship'sownersideisalsotheforeignkeyfortheownedentity.
Considerthefollowingdiagram.
TheSupplierentityhasa1-1relationshipwiththeSupplierStatisticsentity.ASupplierisidentifiedbytheIDkeyuniquelywhichisalsotheprimarykeyoftheSUPPLIERtable.EachSupplierhasanassociatedsetofStatisticslikethenumberofordersplaced,acceptedanddeliveredontimebyagivenSupplier.ThesestatisticsarepersistedintheSUPPLIER_STATISTICStable.TherecordsintheSUPPLIERandSUPPLIER_STATISTICStablearejoinedbytheIDofthesupplier.TheIDcolumnintheSUPPLIERtableisalsoaforeignkeywhichreferencestheSUPPLIER_IDcolumnintheSUPPLIER_STATISTICStable.
TheEJB3entityclassesfortheaboverelationshiparegivenbelow.
packagecom.tutorial.entity;
importjava.io.Serializable;
importjavax.persistence.*;
/**
*ThepersistentclassfortheSUPPLIERdatabasetable.
*
*/
@Entity
publicclassSupplierimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privatelongid;
privateStringname;
//uni-directionalone-to-oneassociationtoSupplierStatistic
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
@JoinColumn(name="ID",insertable=false,updatable=false)
privateSupplierStatisticsupplierStatistic;
publicSupplier(){
supplierStatistic=newSupplierStatistic();
}
publiclonggetId(){
returnthis.id;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetName(){
returnthis.name;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicSupplierStatisticgetSupplierStatistic(){
returnthis.supplierStatistic;
}
@PrePersist
publicvoidinitializeSupplierStatistic(){
this.supplierStatistic.setSupplierId(id);
}
}
packagecom.tutorial.entity;
importjava.io.Serializable;
importjavax.persistence.*;
importjava.math.BigDecimal;
/**
*ThepersistentclassfortheSUPPLIER_STATISTICSdatabasetable.
*/
@Entity
@Table(name="SUPPLIER_STATISTICS")
publicclassSupplierStatisticimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="SUPPLIER_ID")
privatelongsupplierId;
@Column(name="ORDERS_ACCEPTED")
privateBigDecimalordersAccepted;
@Column(name="ORDERS_DELIVERED_ON_TIME")
privateBigDecimalordersDeliveredOnTime;
@Column(name="ORDERS_PLACED")
privateBigDecimalordersPlaced;
SupplierStatistic(){}
publiclonggetSupplierId(){
returnthis.supplierId;
}
publicvoidsetSupplierId(longsupplierId){
this.supplierId=supplierId;
}
publicBigDecimalgetOrdersAccepted(){
returnthis.ordersAccepted;
}
publicvoidsetOrdersAccepted(BigDecimalordersAccepted){
this.ordersAccepted=ordersAccepted;
}
publicBigDecimalgetOrdersDeliveredOnTime(){
returnthis.ordersDeliveredOnTime;
}
publicvoidsetOrdersDeliveredOnTime(BigDecimalordersDeliveredOnTime){
this.ordersDeliveredOnTime=ordersDeliveredOnTime;
}
publicBigDecimalgetOrdersPlaced(){
returnthis.ordersPlaced;
}
publicvoidsetOrdersPlaced(BigDecimalordersPlaced){
this.ordersPlaced=ordersPlaced;
}
}
Noticethesalientfeaturesoftheentitymappings.
TherelationshipisdefinedasaOne-way1-1mappingfromtheSupplier,whichistheowneroftherelationshiptotheSupplierStatisticentity.
//uni-directionalone-to-oneassociationtoSupplierStatistic
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
@JoinColumn(name="ID",insertable=false,updatable=false)
privateSupplierStatisticsupplierStatistic;
The@JoinColumnannotationhastheattributesinsertable=falseandupdatable=false.ThisisbecausetheIDcolumnwhichisaprimarykeyalsohappenstobetheforeignkeyfortheSupplierStatisticentity.Sincewedon'tneedtopersistanadditionalcolumntopersisttherelationshipwhichisimplicitlydefinedbytheprimarykey,wemarktheJoinColumnasinsertableandupdateable=false.OtherwiseyouwillrunintoerrorsdependinguponyourJPAprovider.
WithEclipseLinkJPAprovideravailablewithOracleEnterprisePackforEclipse(OEPE)Iwasgettingthefollowingerrorwithouttheseattributes.
javax.persistence.RollbackException:Exception[EclipseLink-4002](EclipsePersistenceServices-1.1.2.v20090612-r4475):org.eclipse.persistence.exceptions.DatabaseException
InternalException:java.sql.SQLSyntaxErrorException:ORA-00957:duplicatecolumnname
ErrorCode:957
Call:INSERTINTOSUPPLIER(ID,NAME,ID)VALUES(?,?,?)
bind=>[4502,SupplierName1,4502]
ThesupplierStatisticentityisimplicitlycreatedwhentheSupplieriscreated.Refertotheconstructor.TheOneToOnerelationshipismarkedasCascadeType.PERSISTsotheSupplierStatisticentitywillbepersistedalongwiththeSupplierentity.
publicSupplier(){
supplierStatistic=newSupplierStatistic();
}
WhatabouttheSUPPLIER_IDcolumnvaluefortheSupplierStatisticentity?ItneedstobethesamevalueastheparentSupplier'sIDvalue.ThisisachievedbyinjectingtheIDoftheparentintothechildbeforepersistingthem.TheinitialiazeSupplierStatisticmethodisannotatedwiththe@PrePresistannonation.
@PrePersist
publicvoidinitializeSupplierStatistic(){
this.supplierStatistic.setSupplierId(id);
}
Thisensuresthattheidfieldvaluethathasbeeneitherauto-generatedorretrievedfromthesequencetable(dependinguponthegenerationstrategyfortheprimarykey)bytheJPAproviderispassedontothechildentitytherebydefiningthe1-1association.
AsabestpracticetheconstructorfortheSupplierStatisticclassisnotpublic,sothereisnoexplicitwaytocreateandpersistaSupplierStatisticentity.Itgetscreatedandpersistedonlyinthecontextoftheparent.CorrespondinglyaSupplierStatisticentityisremovedalongwiththeparentSupplier,sincewealsohaveCascadeType.REMOVEontherelationship.
Thispatterncanbeappliedtoothersituationswherethesameprimarykeyvalueissharedbetweenthetwoentities,forexampleCustomerandContactwhichcansharetheCUSTOMER_IDhasthecommonkey.
Appendix
DDLfortheSUPPLIERandSUPPLIER_STATISTICStablesfortheOracleDatabase10gExpressEdition
Considerthefollowingdiagram.
TheSupplierentityhasa1-1relationshipwiththeSupplierStatisticsentity.ASupplierisidentifiedbytheIDkeyuniquelywhichisalsotheprimarykeyoftheSUPPLIERtable.EachSupplierhasanassociatedsetofStatisticslikethenumberofordersplaced,acceptedanddeliveredontimebyagivenSupplier.ThesestatisticsarepersistedintheSUPPLIER_STATISTICStable.TherecordsintheSUPPLIERandSUPPLIER_STATISTICStablearejoinedbytheIDofthesupplier.TheIDcolumnintheSUPPLIERtableisalsoaforeignkeywhichreferencestheSUPPLIER_IDcolumnintheSUPPLIER_STATISTICStable.
TheEJB3entityclassesfortheaboverelationshiparegivenbelow.
packagecom.tutorial.entity;
importjava.io.Serializable;
importjavax.persistence.*;
/**
*ThepersistentclassfortheSUPPLIERdatabasetable.
*
*/
@Entity
publicclassSupplierimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
privatelongid;
privateStringname;
//uni-directionalone-to-oneassociationtoSupplierStatistic
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
@JoinColumn(name="ID",insertable=false,updatable=false)
privateSupplierStatisticsupplierStatistic;
publicSupplier(){
supplierStatistic=newSupplierStatistic();
}
publiclonggetId(){
returnthis.id;
}
publicvoidsetId(longid){
this.id=id;
}
publicStringgetName(){
returnthis.name;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicSupplierStatisticgetSupplierStatistic(){
returnthis.supplierStatistic;
}
@PrePersist
publicvoidinitializeSupplierStatistic(){
this.supplierStatistic.setSupplierId(id);
}
}
packagecom.tutorial.entity;
importjava.io.Serializable;
importjavax.persistence.*;
importjava.math.BigDecimal;
/**
*ThepersistentclassfortheSUPPLIER_STATISTICSdatabasetable.
*/
@Entity
@Table(name="SUPPLIER_STATISTICS")
publicclassSupplierStatisticimplementsSerializable{
privatestaticfinallongserialVersionUID=1L;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="SUPPLIER_ID")
privatelongsupplierId;
@Column(name="ORDERS_ACCEPTED")
privateBigDecimalordersAccepted;
@Column(name="ORDERS_DELIVERED_ON_TIME")
privateBigDecimalordersDeliveredOnTime;
@Column(name="ORDERS_PLACED")
privateBigDecimalordersPlaced;
SupplierStatistic(){}
publiclonggetSupplierId(){
returnthis.supplierId;
}
publicvoidsetSupplierId(longsupplierId){
this.supplierId=supplierId;
}
publicBigDecimalgetOrdersAccepted(){
returnthis.ordersAccepted;
}
publicvoidsetOrdersAccepted(BigDecimalordersAccepted){
this.ordersAccepted=ordersAccepted;
}
publicBigDecimalgetOrdersDeliveredOnTime(){
returnthis.ordersDeliveredOnTime;
}
publicvoidsetOrdersDeliveredOnTime(BigDecimalordersDeliveredOnTime){
this.ordersDeliveredOnTime=ordersDeliveredOnTime;
}
publicBigDecimalgetOrdersPlaced(){
returnthis.ordersPlaced;
}
publicvoidsetOrdersPlaced(BigDecimalordersPlaced){
this.ordersPlaced=ordersPlaced;
}
}
Noticethesalientfeaturesoftheentitymappings.
TherelationshipisdefinedasaOne-way1-1mappingfromtheSupplier,whichistheowneroftherelationshiptotheSupplierStatisticentity.
//uni-directionalone-to-oneassociationtoSupplierStatistic
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE,CascadeType.REFRESH})
@JoinColumn(name="ID",insertable=false,updatable=false)
privateSupplierStatisticsupplierStatistic;
The@JoinColumnannotationhastheattributesinsertable=falseandupdatable=false.ThisisbecausetheIDcolumnwhichisaprimarykeyalsohappenstobetheforeignkeyfortheSupplierStatisticentity.Sincewedon'tneedtopersistanadditionalcolumntopersisttherelationshipwhichisimplicitlydefinedbytheprimarykey,wemarktheJoinColumnasinsertableandupdateable=false.OtherwiseyouwillrunintoerrorsdependinguponyourJPAprovider.
WithEclipseLinkJPAprovideravailablewithOracleEnterprisePackforEclipse(OEPE)Iwasgettingthefollowingerrorwithouttheseattributes.
javax.persistence.RollbackException:Exception[EclipseLink-4002](EclipsePersistenceServices-1.1.2.v20090612-r4475):org.eclipse.persistence.exceptions.DatabaseException
InternalException:java.sql.SQLSyntaxErrorException:ORA-00957:duplicatecolumnname
ErrorCode:957
Call:INSERTINTOSUPPLIER(ID,NAME,ID)VALUES(?,?,?)
bind=>[4502,SupplierName1,4502]
ThesupplierStatisticentityisimplicitlycreatedwhentheSupplieriscreated.Refertotheconstructor.TheOneToOnerelationshipismarkedasCascadeType.PERSISTsotheSupplierStatisticentitywillbepersistedalongwiththeSupplierentity.
publicSupplier(){
supplierStatistic=newSupplierStatistic();
}
WhatabouttheSUPPLIER_IDcolumnvaluefortheSupplierStatisticentity?ItneedstobethesamevalueastheparentSupplier'sIDvalue.ThisisachievedbyinjectingtheIDoftheparentintothechildbeforepersistingthem.TheinitialiazeSupplierStatisticmethodisannotatedwiththe@PrePresistannonation.
@PrePersist
publicvoidinitializeSupplierStatistic(){
this.supplierStatistic.setSupplierId(id);
}
Thisensuresthattheidfieldvaluethathasbeeneitherauto-generatedorretrievedfromthesequencetable(dependinguponthegenerationstrategyfortheprimarykey)bytheJPAproviderispassedontothechildentitytherebydefiningthe1-1association.
AsabestpracticetheconstructorfortheSupplierStatisticclassisnotpublic,sothereisnoexplicitwaytocreateandpersistaSupplierStatisticentity.Itgetscreatedandpersistedonlyinthecontextoftheparent.CorrespondinglyaSupplierStatisticentityisremovedalongwiththeparentSupplier,sincewealsohaveCascadeType.REMOVEontherelationship.
Thispatterncanbeappliedtoothersituationswherethesameprimarykeyvalueissharedbetweenthetwoentities,forexampleCustomerandContactwhichcansharetheCUSTOMER_IDhasthecommonkey.
Appendix
DDLfortheSUPPLIERandSUPPLIER_STATISTICStablesfortheOracleDatabase10gExpressEdition
CREATETABLE"SUPPLIER"
("ID"NUMBERNOTNULLENABLE,
"NAME"VARCHAR2(4000),
CONSTRAINT"SUPPLIER_PK"PRIMARYKEY("ID")ENABLE,
CONSTRAINT"SUPPLIER_FK"FOREIGNKEY("ID")
REFERENCES"SUPPLIER_STATISTICS"("SUPPLIER_ID")ENABLE
)
CREATETABLE"SUPPLIER_STATISTICS"
("SUPPLIER_ID"NUMBERNOTNULLENABLE,
"ORDERS_PLACED"NUMBER,
"ORDERS_ACCEPTED"NUMBER,
"ORDERS_DELIVERED_ON_TIME"NUMBER,
CONSTRAINT"SUPPLIER_STATISTICS_PK"PRIMARYKEY("SUPPLIER_ID")ENABLE
)
相关文章推荐
- sql: Query to Display Foreign Key Relationships and Name of the Constraint for Each Table in Database
- MySQL - EF : The value for column 'IsPrimaryKey' in table 'TableDetails' is DBNull
- Cannot insert explicit value for identity column in table ‘table’ when IDENTITY_INSERT is set to OFF
- The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP or FOR XML is also specified.
- Find out all the Primary Key and Foreign Key Constraints in a table
- 168.You execute this command to drop the ITEM table, which has the primary key referred in the ORDER
- MySQL - Entity : The value for column 'IsPrimaryKey' in table 'TableDetails' is DBNull
- PRB: "Requested Registry Access Is Not Allowed" Error Message When ASP.NET Application Tries to Write New EventSource in the Eve
- Cannot insert explicit value for identity column in table 'settings' when IDENTITY_INSERT is set to OFF.
- System.Data.SqlClient.SqlException: Cannot insert explicit value for identity column in table 'Food' when IDENTITY_INSERT is set to OFF
- Cannot insert explicit value for identity column in table 'settings' when IDENTITY_INSERT is set to OFF.
- An explicit value for the identity column in table can only be specified when a column list is used and IDENTITY_INSERT is ON
- How to filter the ManyToManyField or ForeignKey in modelForm?
- 解决The current branch is not configured for pull No value for key branch.master.merge found in config
- The origin server did not find a current representation for the target resource or is not willing to
- Resolution to the record count increasing of the file exported from DB when ‘0A’ is included in it
- This is probably a good time to review the order in which SELECT statement clauses are to be specified. Table 10.2 lists all the clauses we have learned thus far, in the order they must be used.
- How to load the specified mscordacwks.dll for managed debugging when multiple .NET runtime are loaded in one process
- MySQL 表分区 A PRIMARY KEY must include all columns in the table's partitioning function
- Native Client (NaCl) is an open-source technology for running native compiled code in the browser