I have a NamedQuery like bellow:
#Entity
#DiscriminatorValue(value = "20")
#NamedQueries(value = { #NamedQuery(name = "SituacaoFluxo.findAll", query = "SELECT c FROM SituacaoFluxo c ORDER BY c.descricao") })
public class SituacaoFluxo extends BaseSituacao {
public static final String FIND_ALL = "SituacaoFluxo.findAll";
}
The field descricao exists in class BaseSituacao. But Eclipse show the following error:
The state field path 'c.descricao' cannot be resolved to a valid
See my BaseSituacao class
#Entity
#Table(name = "base_situacao")
#Inheritance(strategy = javax.persistence.InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "tipo", discriminatorType = javax.persistence.DiscriminatorType.INTEGER)
public class BaseSituacao extends AbstractBean {
I have a similar query with a hibernate entity subclass in my project.
I tried to replicate your problem but was unsuccessful.
I do use the following annotation:
#PrimaryKeyJoinColumn(name="primary_key_id_field")
where primary_key_id_field is the unique key of the base class.
Add this just above the class declaration.
You could try that and see if it helps.
Related
I have such entity structure
#MappedSuperclass
public abstract class Base {
UUID id;
}
#MappedSuperclass
public abstract class Parent<C extends Child> extends Base {
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<C> children;
}
#MappedSuperclass
public abstract class Child<P extends Parent> extends Base {
#JoinColumn(name = "parent_id", referencedColumnName = "id")
#ManyToOne(optional = false)
private P parent;
}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "ap")
public class AP extends Parent<AC> {}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "ac")
public class AC extends Child<AP> {}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "bp")
public class BP extends Parent<BC> {}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "bc")
public class BC extends Child<BP> {}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "cp")
public class CP extends Parent<CC> {}
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#Table(name = "cc")
public class CC extends Child<CP> {
String value;
}
I do criteria query
CriteriaQuery<Long> cq = getEntityManager().getCriteriaBuilder().createQuery(Long.class);
Root<CP> rt = cq.from(CP.class);
Path child = rt.join("children");
final CriteriaBuilder criteriaBuilder = getEntityManager().getCriteriaBuilder();
cq.select(criteriaBuilder.count(rt));
cq.where(criteriaBuilder.equal(child.get("value"), "exists"));
TypedQuery<Long> q = getEntityManager().createQuery(cq);
Long res = q.getSingleResult()
and get error on line with where clause:
java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [value] on this ManagedType [Base]
After debugging a while I've found out that Parent meta class in entity manager's meta model keeps property children as List of AC. AC obviously doesn't contains field "value".
Any idea how to fix this error?
I think there is no easy fix. Unless you are willing to move value to AC and make CC to extend AC<CP>. Or something alike.
This behavior is because of type erasure.
The actual generic type of children is not available at runtime because compiler casts list to generic type List<AC> based on the upper bound AC.
See also this great answer that explained this thing to me quite well.
After query it is possible to check and cast the list / items to actual type but not at all sure if it is possible within CriteriaQuery.
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...
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
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.
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.