Reputation: 5043
I have a simple class mapped with JPA:
@Entity
@Table(name = "SPONSOR")
public class Sponsor extends PersistableBusinessObjectBase implements SponsorContract {
@PortableSequenceGenerator(name = "SEQ_SPONSOR_CODE")
@GeneratedValue(generator = "SEQ_SPONSOR_CODE")
@Id
@Column(name = "SPONSOR_CODE")
private String sponsorCode;
@Column(name = "ACRONYM")
private String acronym;
@Column(name = "AUDIT_REPORT_SENT_FOR_FY")
private String auditReportSentForFy;
@Column(name = "CAGE_NUMBER")
private String cageNumber;
@Column(name = "COUNTRY_CODE")
private String countryCode;
@Column(name = "DODAC_NUMBER")
private String dodacNumber;
@Column(name = "DUN_AND_BRADSTREET_NUMBER")
private String dunAndBradstreetNumber;
@Column(name = "DUNS_PLUS_FOUR_NUMBER")
private String dunsPlusFourNumber;
@Column(name = "OWNED_BY_UNIT")
private String ownedByUnit;
@Column(name = "POSTAL_CODE")
private String postalCode;
@Column(name = "ROLODEX_ID")
private Integer rolodexId;
@Column(name = "SPONSOR_NAME")
private String sponsorName;
@Column(name = "SPONSOR_TYPE_CODE")
private String sponsorTypeCode;
@Column(name = "STATE")
private String state;
@Column(name = "CREATE_USER")
private String createUser;
@Column(name = "ACTV_IND")
@Convert(converter = BooleanYNConverter.class)
private boolean active;
@ManyToOne(cascade = { CascadeType.REFRESH })
@JoinColumn(name = "SPONSOR_TYPE_CODE", referencedColumnName = "SPONSOR_TYPE_CODE", insertable = false, updatable = false)
private SponsorType sponsorType;
@ManyToOne(cascade = { CascadeType.REFRESH })
@JoinColumn(name = "OWNED_BY_UNIT", referencedColumnName = "UNIT_NUMBER", insertable = false, updatable = false)
private Unit unit;
@ManyToOne(cascade = { CascadeType.REFRESH })
@JoinColumn(name = "ROLODEX_ID", referencedColumnName = "ROLODEX_ID", insertable = false, updatable = false)
private Rolodex rolodex;
....
I have extended that class into a very simple class
@Entity
public class SponsorMaintainableBo extends Sponsor {
}
This is exactly what I need for SponsorMaintainableBo. It is a duplicate of Sponsor, and is read from the same table as Sponsor. This is needed for our query framework that is controlled through some xml documents, and needs to be a separate object for what I am doing. SponsorMaintainableBo is needed to plug into to query/maintenance framework for custom detailing we don't want in the main parent document. When I try and use SponsorMaintainableBo, I get the following error:
org.springframework.orm.jpa.JpaSystemException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'DTYPE' in 'field list'
Error Code: 1054
Call: SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?
bind => [3 parameters bound]
Query: ReadAllQuery(referenceClass=SponsorMaintainableBo sql="SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?"); nested exception is javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.2.v20140319-9ad6abd): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'DTYPE' in 'field list'
Error Code: 1054
Call: SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?
bind => [3 parameters bound]
Query: ReadAllQuery(referenceClass=SponsorMaintainableBo sql="SELECT SPONSOR_CODE AS a1, DTYPE AS a2, ACRONYM AS a3, ACTV_IND AS a4, AUDIT_REPORT_SENT_FOR_FY AS a5, CAGE_NUMBER AS a6, COUNTRY_CODE AS a7, CREATE_USER AS a8, DODAC_NUMBER AS a9, DUN_AND_BRADSTREET_NUMBER AS a10, DUNS_PLUS_FOUR_NUMBER AS a11, OBJ_ID AS a12, OWNED_BY_UNIT AS a13, POSTAL_CODE AS a14, ROLODEX_ID AS a15, SPONSOR_NAME AS a16, SPONSOR_TYPE_CODE AS a17, STATE AS a18, UPDATE_TIMESTAMP AS a19, UPDATE_USER AS a20, VER_NBR AS a21 FROM SPONSOR WHERE (DTYPE = ?) LIMIT ?, ?")
at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:321)
at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:120)
I'm not sure the best way to map the sub class and inherit all the JPA mappings. Please advise.
Upvotes: 0
Views: 2281
Reputation: 22128
You haven't specified the details of what you have in SponsorMaintainableBo
so its difficult to understand what you have in there.
You haven't quite extended your Entity in the right way. You need to give hints how you are going to extend the original table in the database (everything bunched in the same table, known as SINGLE_TABLE
? a new table with one-to-one references known as JOINED
? a copy of the table with the new fields known as TABLE_PER_CLASS
?)
You should look at http://en.wikibooks.org/wiki/Java_Persistence/Inheritance to understand how to implement this properly.
UPDATE
Although it is still not quite clear what SponsorMaintainableBO
is actually doing, from the details you added I suspect that the reason is that you are using the wrong design pattern here. If you extend a JPA Entity Bean, the system will expect that you are doing that to add additional fields, so it also adds the mechanism to differentiate between the two entities (the superclass and the subclass) in the database. By default, as indicated by @Predrag it expects a field called DTYPE
to your table, so that a row can be identified whether it is an instance of the superclass or the subclass (inheritance is not something supported by standard SQL). There are alternative mechanisms you can use, such as completely separate tables, or 2 tables joined together by a foreign key with the 2nd table adding only the fields added by the subclass.
Now from what you've said, you don't seem to be doing (or needing) any of this. If I understood correctly you are overloading the responsibility of the Entity bean with further behaviour expected from your framework. Entity Beans are designed to be just Beans, i.e. carriers of data. If you extend them JPA understands that you are doing it for a reason, to add more data (i.e. more fields). What you seem to want is a wrapper of your Entity so that it also plugs into your framework. This way both concerns are kept separate but still tied together.
I don't know what your framework is expecting from SponsorMaintainableBo
but my inclination is that you should use a different approach. Instead of making SponsorMaintainableBo
extend Sponsor
you probably should put an instance of Sponsor
inside SponsorMaintainableBo
thus changing the relationship from SponsorMaintainableBo
-is-a- Sponsor
to a SponsorMaintainableBo
-has-a- Sponsor
. You could make Sponsor
a constructor parameter and immutable like this if you want both instances to be absolutely coupled:
public class SponsorMaintainableBo
{
private final Sponsor sponsor;
public SponsorMaintainableBo(Sponsor sponsor)
{
this.sponsor = sponsor;
}
public Sponsor getSponsor()
{
return this.sponsor;
}
//... rest of the methods expected by the framework
}
If the above is not enough, and the framework expects some fields in SponsorMaintainableBo
which are in common with Sponsor
you should then use the Decorator pattern. I presume you already have this in SponsorContract
so most probably what you need to do is:
public class SponsorMaintainableBo implements SponsorContract
{
private final Sponsor sponsor;
public SponsorMaintainableBo(Sponsor sponsor)
{
this.sponsor = sponsor;
}
public Sponsor getSponsor()
{
return this.sponsor;
}
//... rest of the methods specified by `SponsorContract`
//... rest of the methods expected by the framework
}
The methods required by SponsorContract
just delegate the function call to the underlying Sponsor
instance.
(Note that the full Decorator pattern is designed to chain multiple instances together so it would add SponsorContract sponsor
instead of Sponsor sponsor
to your SponsorMaintainableBo
so that you could even chain other behaviour wrapping around your Entity, but I don't think you need that level of complexity)
Upvotes: 0
Reputation: 24403
Here is some information about JPA entity inheritance.
You have to configure the inheritance on your entities, it's not enough just to extend the class. If you want to have SponsorMaintainableBo
in a separate table, then annotate Sponsor
entity with @Inheritance(strategy=TABLE_PER_CLASS)
. There are plenty of examples online for configuring different types of inheritance.
public enum InheritanceType {
SINGLE_TABLE,
JOINED,
TABLE_PER_CLASS
};
Unknown column 'DTYPE' in 'field list'
means that SINGLE_TABLE
is the default inheritance type, and that your JPA provider is looking for (default named) column DTYPE
in target table, in order to determine the exact type of the entity.
Upvotes: 3