Retrieve only the superclass from a class hierarch

2019-06-28 05:36发布

I have an scenario as the following:

@Entity
@Table(name = "ANIMAL")
@Inheritance(strategy = InheritanceType.JOINED)

public class Animal implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "S_ANIMAL")
    @SequenceGenerator(name = "S_ANIMAL", sequenceName = "S_ANIMAL", allocationSize = 1)
    public int getNumero() {
        return numero;
    }

    public void setNumero(int numero) {
        this.numero = numero;
    }
        .
        .
        .
}

and as the subclass:

@Entity
@Table(name = "DOG")
public class Dog extends Animal {

    private static final long serialVersionUID = -7341592543130659641L;
        .
        .
        .
}

I have a JPA Select statement like this:

SELECT a FROM Animal a;

I'm using Hibernate 3.3.1

As I can see the framework retrieves instances of Animal and also of Dog using a left outer join.

Is there a way to Select only the "part" Animal? I mean, the previous Select will get all the Animals, those that are only Animals but not Dogs and those that are Dogs.

I want them all, but in the case of Dogs I want to only retrieve the "Animal part" of them.

I found the @org.hibernate.annotations.Entity(polymorphism = PolymorphismType.EXPLICIT) but as I could see this only works if Animal isn't an @Entity.

Thanks a lot.

2条回答
老娘就宠你
2楼-- · 2019-06-28 06:15

Short answer: The behaviour you describe complies with JPA standard. There is no JPA standard way to restrict the JPA provider to retrieve only the superclass.

The provider can choose query implementation logic to achieve functionality, consistency & performance. As long as it respects your entity annotations and returns the requested information in the query all is good. Think of the outer join to Dog as private implementation detail that should not concern you. The provider has coded an outer join to assist performance and consistency.

Consider:

  • JPA is defined to work on java object Entities not tables
  • Root of your Entity hierarchy, Animal, is not abstract, so you can create an instance and persist it.
  • You have a default value for Animal @DescriminatorColumn and @DescriminatorType - so Animal table will have a discriminator column added with name "DTYPE" and type "some String type". You have a default value for @DescriminatorValue - will be equal to the Entity name: Animal. So Animal.DTYPE column = "Animal" when you create this entity.
  • The Entity Dog has a superclass Animal. The default value is also used for its @DescriminatorValue - Dog. So Animal.DTYPE column = "Dog" when you create this entity.
  • Java class restrictions ensure that whenever a Dog object exists a corresponding Animal superclass object also exists.
  • Very often, when you have an Entity Animal loaded into JPA persistence context, with a @DescriminatorValue (value stored in DTYPE column) = "Dog", then it is very useful to have Dog object loaded into PC for consistency. Even though it is not required by the JPA standard.
  • The inheritance relationship cannot be specified to be EAGER or LAZY (like a basic type field or entity relationship field). If you needed to read/update dog properties and the Dog class was not loaded what would you do? Run a separate query to reload it? This would hurt consistency and performance greatly.
  • The main concern for performance is the total number of separate SQL commands sent to the DB.
    In terms of time taken: query with animal table is only slightly faster (10s of microseconds???) than query with animal outer joined to dog, but is much faster than two separate queries (one for animal and one for dog)
查看更多
再贱就再见
3楼-- · 2019-06-28 06:21

Actually, there is a way to get just the superclass: you just need to use the native query from JPA. In my case, I am using JPA Repositories. Therefore, it would be something like that:

@Query(value = "SELECT * FROM animal", nativeQuery = true)
List<Resource> findAllAnimal();

The flag nativeQuery as true allow running the native SQL on database.

If you are using Entity Manager then check this out: https://www.thoughts-on-java.org/jpa-native-queries/

查看更多
登录 后发表回答