Consider the following hierarchy, where entities WidgetA
and WidgetB
extend an abstract Widget
superclass:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Widget implements Serializable {
@Column(name="serialNumber", length=64, nullable=false, unique=true)
private String serialNumber;
...
and
@Entity
public class WidgetA extends Widget implements Serializable {
...
and
@Entity
public class WidgetB extends Widget implements Serializable {
...
I need to search for Widgets by serialNumber
, but I don't know the concrete type of the Widget I'm searching for at runtime. What is the correct way to search for widgets by serialNumber
such that if the serialNumber
is that of a WidgetA
, then an instance of WidgetA
gets returned, and so on?
I am trying to use a findyBySerialNumber()
in the Widget
DAO, and I'm getting an error telling me I can't instantiate an abstract class, which makes sense, but I thought the persistence provider would know how to look in the concrete child entity tables and return the correct instance. Can I make it do this?
I am using "Spring Data JPA", so the Widget DAO is really simple:
public interface WidgetDAO extends JpaRepository<Widget, Long> {
public Widget findBySerialNumber(String serialNumber);
}
Hibernate supports that query just fine, and will happily return an instance of the correct subclass. Without knowing what it is in the Spring Data implementation that is trying to make an instance of Widget, you should be able to just declare the query and have it run it directly, rather than using the parser.
It seems you didn't specify a discriminator explicitly for your widget hierarchy. I think you can try to define it explicitly because Spring Data will manipulate bytecode to generate the queries, and so I suspect SpringData need to have those values explicitely defined.
Additionally in subclasses you need to indicate the discriminator value for each subclass.
-
-
Your objects and annotations look fine to me. I was able to take them, save a widget to a database, and fetch it out without a problem.
I think the the problem is in your data. Hibernate is probably finding a row in the
Widget
table that does not have a corresponding row in any of the sub class tables, and is therefore trying to create an instance of the superclass, and failing.With
InheritanceType.JOINED
, you can either specify a discriminator, or let it do it for you (I believe by checking whether a row with that ID exists in the subclass table). But either way, you have to check your data to make sure there's not an entry in the super class table without a matching subclass row.As a rule, I support @ben75's recommendation that you do explicitly specify
@Discriminator
for class hierarchies. It's better to have control over your discriminator values, so that later code changes don't alter the values in unexpected ways.