I'm using EJB 3 with Hibernate 4 on Weblogic 10.3.4.
I have a problem when I try to select an entity based on a property that doesn't exists in its parent entity:
I have in my system something like this: A basic abstract VehicleDefinition class and two concrete subclasses - CarDefinition and TruckDefinition.
Also, I have a basic abstract VehicleInstance and two concrete subclasses - CarInstance and TruckInstance.
In VehicleInstance I have a VehicleDefinition field.
In the TruckDefinition class I map a field (Height) that doesn't exists In VehicleDefinition or in CarDefinition. The problem is that with the mentioned mapping, I can't use an HQL to select a TruckInstance by a the field of TruckDefintion (i.e. A TruckInstance by height), because TruckInstance only "knows" VehicleDefinition, not TruckDefinition.
The mappings goes something like this:
#Entity
#Table(name = "VEHICLES" uniqueConstraints = {#UniqueConstraint(columnNames = {"TYPE_NAME"}) })
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "VEHICLE_TYPE", discriminatorType = DiscriminatorType.INTEGER)
public abstract class VehicleDefinition {...}
#Entity
#DiscriminatorValue("222")
public class CarDefenition extends VehicleDefinition {...}
#Entity
#DiscriminatorValue("555")
public class TruckDefenition extends VehicleDefinition{
...
private Integer mHeight;
#Column(name = "TRUCK_HIGHT")
public Integer getHeight()
{
return mHeight;
}
}
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorFormula("CASE WHEN 222 = (SELECT a.VEHICLE_TYPE FROM VEHICLES a WHERE a.id = VEHICLE_ID) THEN 222 ELSE 555 END")
#Table(name = "VEHICLE_INSTANCES" uniqueConstraints = {#UniqueConstraint(columnNames = {"VEHICLE_ID", "LPLATE"}) })
public abstract class VehicleInstance {
...
private VehicleDefinition mDefinition
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "VEHICLE_ID" referencedColumnName = "ID", nullable = false)
public VehicleDefenition getDefinition()
{
return mDefinition;
}
}
#Entity
#DiscriminatorValue("222")
public class CarInstance extends VehicleInstance {...}
#Entity
#DiscriminatorValue("555")
public class TruckInstance extends VehicleInstance {...}
I tried to refactore he classes, making getDefinition in VehicleInstance abstract, and having TruckInstance and CarInstance implement, both returning their repectivetypes, but then I couldn't figure out how two map the new methods. Should I keep the original annotations at VehicleInstance? Should both of them point to VEHICLE_ID? Every combination I tried seemed to fail.
So in conclusion - How can I map VehicleInstance, CarInstance and TruckInstance so that I can select in HQL a TruckInstance based on its Height property?
Thanks in advance!
Related
Entities:
#Entity
#Table(name = "ITEM")
#Inheritance(strategy = InheritanceType.JOINED)
public class Item extends Base {
#OneToOne(mappedBy = "item")
protected Doc doc;
}
#MappedSuperclass
public abstract class Doc extends BaseDoc {
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "itemId")
private Item item;
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class BaseDoc extends Base {}
Tables:
BASEDOC
- itemId int8
(other attributes)
ITEM
(other attributes)
BASE
(other attributes)
During runtime it fails with:
Caused by:
org.hibernate.AnnotationException: Unknown mappedBy in: com.ghiton.updater.entity.Item.doc, referenced property unknown: com.ghiton.updater.entity.Doc.item"}}
I think the reason is the MappedSuperclass, since 'item' is stored in the Base table. Is there a practice to solve these type of cases?
I found that "Mapped superclasses can't be targets of entity relationships.", in this case how I can achieve that Doc to be persisted into the BaseDoc table?
At DB level it has all the columns what are needed, so not necessary to have a separate DOC table.
You cant join mappedsuperclass annotated class with entity class. Mappedsuperclases are not an entity
Link
I think you can change your code like this.
#Entity
#Table(name = "ITEM")
#Inheritance(strategy = InheritanceType.JOINED)
public class Item extends Base {
#OneToOne(mappedBy = "item")
protected Doc doc;
}
#Entity
#Table(name = "DOC")
public abstract class Doc extends BaseDoc {
#OneToOne(mappedBy = "doc")
private Item item;
}
#MappedSuperclass
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class BaseDoc extends Base {}
I have two tables A and B:
#Entity
public class A {
}
#Entity
public class B {
private final A a;
private String someBSpecificField;
}
Entity A is already Coded nicely and mapped to an existing table. My job is to create B and for some reason I prefer composition over inheritance between A and B. At the same time I want to have single table for A and B to avoid joins when reading. Can I do like this:
#Entity
#Table(name = "a")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "a_type_enum", discriminatorType =
DiscriminatorType.INTEGER)
#DiscriminatorValue("100")
public class A {
}
#Entity
#Table(name = "a")
#DiscriminatorValue("500")
public class B {
private final A a;
private String someBSpecificField;
}
If the type is a complex object then you need to annotate that type with #Embeddable and use it in your #Entity class.
if you want to override the attribute names for your #Embeddable class so they have different column names, you can do so with the #AttributeOverrides annotation.
I'm trying to mapp Entity (TrainingEntity) to DTO, where one of the fields is a Set with ManyToMany reference to an AbstractEntity (CoachEntity) divided by Single Table into two subclasses: ExternalCoach and InternalCoach.
Both subclasses have different data, therefore require two different mappers.
#Entity
#Table(name = "TRAINING")
public class TrainingEntity extends AbstractEntity {
#ManyToMany()
#JoinTable(name = "TRAINING_EMPLOYEE", joinColumns = { #JoinColumn(name = "TRAINING_ID") }, inverseJoinColumns = {
#JoinColumn(name = "COACH_ID") })
private Set<CoachEntity> coachEntities;
#Column(nullable = false)
private TrainingType trainingType;
......some data....
}
Abstract Coach Entity
#Entity
#Table(name = "COACH")
#DiscriminatorColumn(name = "TYPE", discriminatorType = DiscriminatorType.STRING)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class CoachEntity extends AbstractEntity {
......some data....
}
Coach Subclasses:
#Entity
#DiscriminatorValue("EXTERNAL")
public class ExternalCoachEntity extends CoachEntity {
......some data....
}
#Entity
#DiscriminatorValue("INTERNAL")
public class InternalCoachEntity extends CoachEntity {
......some data....
}
One mapper for Abstract Coach class won't have acces to subclasses methods and fields, so I need two different for External and Internal. Than I would have to use them in TrainingMapper class, but (example of internal):
public class CustomTrainingMapper {
public static TrainingDto toTrainingDto(TrainingEntity trainingEntity){
if(trainingEntity == null){
return null;
}
if(trainingEntity.getTrainingType().equals(TrainingType.INTERNAL)){
Set<CoachEntity> coachEntities = trainingEntity.getCoachEntities();
Set<CoachDto> coachDtos = CustomInternalCoachMapper.toDTOSet((Set<InternalCoachEntity>)coachEntities);
}
I get:
cannot cast from Set<CoachEntity> to Set<InternalCoachEntity>
Without cast it simply doesn't see mappers methods with subclass input.
The method toDTOSet(Set<InternalCoachEntity>) in the type CustomInternalCoachMapper is not applicable for the arguments (Set<CoachEntity>)
When in mapper I change method input to abstract Coach Class it doesn't see subclasses methods and fields.
Part of InternalMapper:
public class CustomInternalCoachMapper {
public static CoachDto toCoachDto(InternalCoachEntity coachEntity) {
if (coachEntity == null) {
return null;
}
EmployeeDto employeeDto = CustomEmployeeMapper.toEmployeeDto(coachEntity.getEmployeeEntity());
return new InternalCoachDto(coachEntity.getId(), coachEntity.getVersion(), coachEntity.getCreateDate(),
coachEntity.getUpdateDate(), coachEntity.getName(), coachEntity.getSurname(), employeeDto);
}
Is it possible to mapp this AbstractEntity Set into subclasses DTOs?
I also tried with AbstractDto for Coaches, but then I'm facing the same problem with no access to subclasses getters and setters.
I have an inheritance relationship of entities with joined type.
#Entity
#Table(name = "MSM_SUBSCRIPTION")
#DiscriminatorColumn(name = "SUBSCRIPTIONTYPE", discriminatorType = DiscriminatorType.STRING, length = 100)
class subscription {
}
#DiscriminatorValue("com.xxx.XXXSubscription")
#Table(name = "XXX")
public class XXXSubscription extends Subscription implements Serializable {
}
When I'm trying to use a named query such as
SELECT s.class AS subscriptiontype,
FROM
Subscription s
It is resulting in the following query
select
case
when s1_.subscriptionId is not null then com.xxx.XXXSubscription
when s.subscriptionId is not null then 'Subscription'
end AS subscriptiontype,
from
MSM_SUBSCRIPTION s
left outer join
XXXSubscription s1_
on s.subscriptionId=s6_.subscriptionId
Which throws an error as below.
-ORA-00904: "COM"."xxx"."MMSSUBSCRIPTION": invalid identifier
As I noticed, there are no tags around the case statement in generated query, on manually firing this query with tags around the DiscriminatorValue 'com.xxx.XXXSubscription', the query is running fine.
Can someone please help ??
try this
you can define super class with #inheritance annotation
#Entity
#Table(name = "MSM_SUBSCRIPTION")
**#Inheritance(strategy = InheritanceType.SINGLE_TABLE)**
#DiscriminatorColumn(name = "SUBSCRIPTIONTYPE", discriminatorType = DiscriminatorType.STRING, length = 100)
class subscription {
}
#DiscriminatorValue("com.xxx.XXXSubscription")
#Table(name = "XXX")
public class XXXSubscription extends Subscription implements Serializable {
}
I've abstract class:
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class A {
...
}
and few extending classes, like:
#Entity
public class B extends A {
...
}
I also have third entity:
#Entity
public class C {
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private A objectA;
...
}
And the question is, how can I construct Spring Data JPA finder in C entity repository to query only objects extending A with desired type?
You can use the name of discriminator value which you've defined "type"
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
#Table(name = "abc")
public abstract class Abc {
....
-------------------------------------------
#Query("select a from Abc a where type = ?1")
List<Abc> findByType(String typeValue);