61776

JPA Mapping with basic class inheritance

Question:

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.

Answer1:

<a href="http://docs.oracle.com/javaee/6/tutorial/doc/bnbqn.html" rel="nofollow">Here</a> 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.

Answer2:

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 <a href="http://en.wikibooks.org/wiki/Java_Persistence/Inheritance" rel="nofollow">http://en.wikibooks.org/wiki/Java_Persistence/Inheritance</a> to understand how to implement this properly.

<strong>UPDATE</strong>

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 <strong>inside</strong> SponsorMaintainableBo thus changing the relationship from SponsorMaintainableBo <em>-is-a-</em> Sponsor to a SponsorMaintainableBo <em>-has-a-</em> 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 <a href="http://en.wikipedia.org/wiki/Decorator_pattern" rel="nofollow">Decorator pattern</a>. 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)

Recommend

  • JPA and eclipselink - Overriding FetchType.Eager
  • JPA 2.0 & MySQL are not respecting case sensitive table names
  • Create custom JPA query function
  • Why EclipseLink maps a NVARCHAR type to an Object?
  • Reading Element attribute value using XStream
  • JPA EntityGraph based on meta model containing MappedSuperclass not possible?
  • Solve apparent need for outside reference to entity inside aggregate (DDD)
  • How do I use multiple databases with JPA?
  • How to update data in Redis and MySQL at the same time?
  • How to fix: The return type of an async method must be void, Task or Task [AppName]
  • How do I get NHibernate to save an entity if I assign it an ID, but generate one otherwise?
  • Applying custom annotation advice to spring data jpa repository
  • Spring @Transactional - javax.persistence.TransactionRequiredException
  • Unable to run SDL program in Eclipse but able to do so in Windows Explorer
  • What is the likely cause of a net::ERR_CONNECTION_ABORTED when uploading a file to Spring
  • How to resolve dependencies from one gradle project to another gradle project in my Eclipse workspac
  • Wrapping text in spinner android
  • Any nice way to generate a timeline view of commits from subversion?
  • Local Development, Apache vs Developer - file permissions
  • How to retrieve information from antrun back to maven?
  • Do query loads all the data in memory
  • aapt.exe'' finished with non-zero exit value 1
  • Salesforce Different WSDL files and when to use
  • AndEngine Applying Transparancy to AndEngine View
  • Automatically associate new Sonar project with custom quality profile and quality gate
  • Jetty 9 HashLoginService
  • Installing Apache MyFaces 2 on WildFly 8.2.0
  • Read a local file using javascript
  • ImageMagick, replace semi-transparent white with opaque white
  • Cannot connect to cassandra from Spark
  • Launch Runnable Jar from Web Start
  • How to recover from a Spring Social ExpiredAuthorizationException
  • How to convert from System.Drawing.Color to Excel.ColorFormat in C#? Change comment color
  • Cross-Platform Protobuf Serialization
  • javascript inside java/jsp code
  • Alternatives to the OPTIONAL fallback SPARQL pattern?
  • How to get icons for entities from eclipse?
  • Android Studio and gradle
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • How can i traverse a binary tree from right to left in java?