Unnable to save discriminator value. (JPA spring data + hibernate) - java

I have following situation:
Base class:
#Entity(name = "BaseEntity")
#Inheritance(strategy= InheritanceType.JOINED)
#DiscriminatorColumn(name="DISCR_COLUMN", discriminatorType = DiscriminatorType.STRING)
#Table(name = "base")
#DiscriminatorOptions(insert = true,force=true)
public abstract class Base implements Serializable {
Subclass:
#Entity(name = "SubclassEntity")
#DiscriminatorValue("A")
#Table(name="subclass")
#PrimaryKeyJoinColumn(name = "subclass_id", referencedColumnName = "base_id")
#DiscriminatorOptions(insert = true,force=true)
public class Subclass extends Base {
Repository:
public interface BaseRepository extends JpaRepository<Base, String>, JpaSpecificationExecutor<Base> {
The only problem I have is when I want to create a new Subclass
repository.saveAndFlush(Base base);
discriminator value is not saved and in DB appears NULL. I supposed it is set automatically by hibernate, isn't it ?

Attention: see comment below (!)
According to http://en.m.wikibooks.org/wiki/Java_Persistence/Inheritance section "Joined, Multiple Table Inheritance":
Hibernate does not support discriminator column for inheritance strategy: joined.

Related

Eclipselink JPA + #Mutitenant + #Inheritance Insert Op Failing - Inconsistent Behavior

#MappedSuperClass
public abstract class BaseMappedSuperClass {
#EmbeddedId
private EmbeddedId id;
}
#Entity
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "typeCol")
public abstract class Vehicle extends BaseMappedSuperClass{
private String name;
}
#Entity(name = "Cycle")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#DiscriminatorValue(value = "Cycle")
public class Cycle extends Vehicle {
private String bellType;
}
#Entity(name = "Bus")
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#DiscriminatorValue(value = "Bus")
public class Bus extends Vehicle {
private String gearType;
}
I have the above entity structure and if I try to do an insert op on the entity Cycle or Bus, it fails inconsistently, because of the missing primary key field (id).
When I tried to debug the JPA codebase, I figured that the tenant discriminator, which is tenant_id in my case is not appended to the table name prefix for the embeddedId field 'Id' and the discriminator column field 'typeCol'.
What is more interesting is that this behavior is not consistent. If I restart my application and try, it works. If I restart again and try,it does not work.
Any help would be appreciated. Version of eclipse link used is 2.5.1.
What is the logic behind the order in which the entities are processed to initialize the metadata?

JPA 2.1 #ForeignKey in inheritance class

I'm migrating to JPA 2.1 and I would like to replace #org.hibernate.annotations.ForeignKey to something in inheritance class.
In fields, ok:
#ManyToOne
#JoinColumn(name = "any_columm_field_id",
foreignKey = #javax.persistence.ForeignKey(name = "any_name_field_fk"))
But in inheritance class, how to do it?
Example code:
Super class
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "ANY_SUPER_TABLE_NAME")
public abstract class AnySuperClass { }
Specific class
#Entity
#Table(name = "ANY_SPECIFIC_TABLE_NAME")
// TODO Replace to JPA 2.1
// #org.hibernate.annotations.ForeignKey(name = "any_specific_any_super_fk")
public class AnySpecificClass extends AnySuperClass { }
Any help?
Thank you for your time.
According to the doc this should do it:
#Entity
#Table(name = "ANY_SPECIFIC_TABLE_NAME")
#PrimaryKeyJoinColumn(foreignKey = #ForeignKey(name = "any_specific_any_super_fk"))
public class AnySpecificClass extends AnySuperClass { }
It's not easy to find the answer though, with the embedded annotation... it's not obvious where you should be using it.
Not sure this will help you a year later...

Hibernate nested discriminator on inherited classes

I have 2 MYSQL tables
table1
id bigint auto increment Primary Key
type Enum ('vegetable','fruit')
color Enum ('green','red','yellow')
table2
id bigint (same as the id in Table 1)
sweet boolean
sour boolean
.. other fields specific to type fruit
Now I'm creating 3 objects, first the parent class
#Entity
#Configurable
#Table(name = "table1")
#DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public class ParentClass {
..
}
Now the second class for vegetable
#Entity
#Configurable
#DiscriminatorValue("vegetable")
#DiscriminatorColumn(name = "color", discriminatorType = DiscriminatorType.STRING)
public class Vegetable extends Parent{
..
}
And thirdly, the fruit class
#Entity
#Configurable
#SecondaryTables({ #SecondaryTable(name = "table2",
pkJoinColumns = { #PrimaryKeyJoinColumn(name = "id", referencedColumnName = "id") }) })
#DiscriminatorValue("fruit")
#DiscriminatorColumn(name = "color", discriminatorType = DiscriminatorType.STRING)
public class Fruit extends Parent{
..
}
I'm needing the second discriminator to add further inherited classes (6 further classes) on Vegetable and Fruit like,
#Entity
#Configurable
#DiscriminatorValue("red")
public class RedVegetable extends Vegetable{
..
}
#Entity
#Configurable
#DiscriminatorValue("green")
public class GreenFruit extends Fruit{
..
}
and so on.
Hibernate isn't letting me do that. What's wrong with my design? Thanks in advance!
Learnt this cannot be done in Hibernate. So found an alternate way to do things by merging the discriminator friends in table1 like Enum ('fruit|red', 'fruit|green', 'vegetable|red'.. & so on).
Please correct me if I was wrong.

Polymorphic query in spring data

I have one base abstract class.
#Entity
#Table(name = "P_FLD")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "FLD_DISCRIMINATOR", columnDefinition = "CHAR(3)")
abstract public class AbstractPassbookField
and some classes that extends it. For example:
#Entity
#DiscriminatorValue("F")
#Table(name = "P_FLD_F")
public class PassbookFileField extends AbstractPassbookField
and i create repository for base entity
public interface PassbookRepository extends CrudRepository<AbstractPassbookField, Long>
I'm running next test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("classpath:test-config.xml")
public class PassbookFieldRepositoryTest {
#Autowired
PassbookRepository passbookRepository;
#PersistenceContext
private EntityManager em;
#Test
public void testSave() {
PassbookFileField passbookFileField = new PassbookFileField();
passbookFileField.setFilename("text.test");
passbookFileField.setTemplate(true);
passbookFileField.setReadonly(true);
passbookFileField.setImageType(ImageType.I);
passbookFileField.setResoltuionType(ImageResolutionType.N);
passbookFileField = passbookRepository.save(passbookFileField);
passbookRepository.findAll();
}
}
passbookRepository.save(passbookFileField) - works well, but
passbookRepository.findAll() gives me an exception
org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException: Object [id=1] was not of the specified subclass [ru.teamlabs.moneybox.commons.model.passbook.field.AbstractPassbookField] : Discriminator: F ; nested exception is org.hibernate.WrongClassException: Object [id=1] was not of the specified subclass [ru.teamlabs.moneybox.commons.model.passbook.field.AbstractPassbookField] : Discriminator: F
Quering through entityManager gives me the same error. What I'm doing wrong?
You haven't given the DiscriminatorValue value for your Super Class thus when retrieving it can not distinguish Super and Sub Classes. Try the following, it must work.
#Entity
#Table(name = "P_FLD")
#DiscriminatorValue("SF")
#Inheritance(strategy = InheritanceType.JOINED)
#DiscriminatorColumn(name = "FLD_DISCRIMINATOR", columnDefinition = "CHAR(3)")
abstract public class AbstractPassbookField
I've found out why it was happening.
#DiscriminatorColumn(name = "FLD_DISCRIMINATOR", columnDefinition = "CHAR(3)")
This string was the problem.
In PassbookFileField i have
#DiscriminatorValue("F")
But repository expected to get entity with discriminator with 3 chars.
Such discriminator
#DiscriminatorValue("F")
or such discriminator column definition
#DiscriminatorColumn(name = "FLD_DISCRIMINATOR", columnDefinition = "CHARACTER VARYING(3)")
solves the problem

Hibernate expecting wrong parameter type in HQL

We have an hierarchy of entities, e.g. abstract Basket and two concrete, which in turn can contain a list of some other items, for example, with exact same hierarchy(SaleBasketItem, ReturnBasketItem).
#Entity
#XStreamAlias("basket")
#DiscriminatorColumn(name = "basket_type")
#DiscriminatorOptions(force = true)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class Basket<T extends BasketItem>
#Entity
#DiscriminatorValue(value = "SALE")
public class SaleBasket extends Basket<SaleBasketItem>
#Entity
#DiscriminatorValue(value = "RETURN")
public class ReturnBasket extends Basket<ReturnBasketItem>
#Entity
#Table(name = "basket_item")
#XStreamAlias("basket_str")
#DiscriminatorColumn(name = "basket_item_type")
#DiscriminatorOptions(force = true)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public abstract class BasketItem<U extends BasketItem, V extends Basket>
#Entity
#DiscriminatorValue(value = "RETURN")
public class ReturnBasketItem extends BasketItem<ReturnBasketItem, ReturnBasket>
#Entity
#DiscriminatorValue(value = "SALE")
public class SaleBasketItem extends BasketItem<SaleBasketItem, SaleBasket>
So, the problem arises when I try to execute hql query like
"SELECT bi FROM " + basketType + "BasketItem bi JOIN bi.basket b JOIN b.saleSession JOIN bi.ware w WHERE b.state = :state"
where basketType is dynamically either "Sale" or "Return". Then I put that query in TypedQuery with type of BasketItem I need and try to setParameter("state", state), where state is some enum representing state of concrete basket (different in each concrete class, not present in abstract class at all), which throws
IllegalArgumentException(java.lang.IllegalArgumentException: Parameter value ... was not matching type)
where type is ReturnBasketState when actual is SaleBasket state, or vice versa.
So the question is - how to force Hibernate to expect correct type for that parameter?
I suppose it's expecting a String as parameter, rather than an Enum. try passing a String instead.

Categories