How to use QueryDSL with SINGLE_TABLE? - sql

I am using JPA with QueryDSL.
Here are my entities with single table inheritance strategy.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "type")
public abstract class Parent {
private int parentId;
private LocalDateTime createdAt;
...
}
#Entity
#DiscriminatorValue("a")
public class A extends Parent {
...
}
#Entity
#DiscriminatorValue("b")
public class B extends Parent {
...
}
#Entity
#DiscriminatorValue("c")
public class C extends Parent {
...
}
I have to write a query with QueryDSL that inquires A and B in order of createdAt value.
If I can't do this with QueryDSL what can I do?

Related

How to write select named query in jpa for EmbeddedId?

I have a JPA entity called Parent and inside that there is embeddedPrimary key as Child
#Entity
#Table(name = "PARENT")
#NamedQuery(?????)
public class Parent implements Serializable {
#EmbeddedId
private ChildPK child;
}
and
#Embeddable
public class ChildPK implements Serializable {
#Column(name = "DEALERID")
private String dealerId;
#Column(name = "BRANDID")
private Long brandId;
..
}
How can I write named Query in Parent class so that i can perform select on dealerId and brandId from ChildPk.
SELECT p FROM Parent p WHERE p.child.dealerId = ? and p.child.brandId=?

Error reading annotations with composite key in EBean

Following this link
I would like to use OneToMany instead ManyToMany annotation, having middle class with composite key in it using Ebean. I have this error:
java.lang.RuntimeException: Error reading annotations for models.SoftwareTagPk
This is my SoftwareTagPk class:
#Embeddable
public class SoftwareTagPk implements Serializable {
#ManyToOne
private Tag tag;
#ManyToOne
private Software software;
...
}
And SoftwareTag class:
#Entity
public class SoftwareTag extends Model {
#EmbeddedId
private SoftwareTagPk pk = new SoftwareTagPk();
#Transient
public Tag getTag() {
return pk.getTag();
}
public void setTag(Tag aTag) {
pk.setTag(aTag);
}
#Transient
public Software getSoftware() {
return pk.getSoftware();
}
public void setSoftware(Software aSoftware) {
pk.setSoftware(aSoftware);
}
}
Also in logs:
Error with association to [class models.Tag] from
[models.SoftwareTagPk.tag]. Is class models.Tag registered?
How to fix it?
To make this code work you have to do:
In your SoftwareTagPk class put only id's of Tag and Software
Move #ManyToOne relations to SoftwareTag class
Add #JoinColumn annotations with attributes updatable and insertable set to false.
Override setters setTag and setSoftware in SoftwareTag class. In these setters you will rewrite id's to composite key.
Main idea of this solution is that SoftwareTag has composite key and #ManyToOne relations and they are mapped to the same collumns.
This is the code:
Tag.java
#Entity
public class Tag extends Model {
#Id
private Integer id;
#OneToMany(mappedBy="tag")
public List<SoftwareTag> softwareTags;
public Integer getId() {
return id;
}
public void setId(Integer aId) {
id=aId;
}
public static Finder<Integer,Tag> find = new Finder<Integer,Tag>(
Integer.class, Tag.class
);
}
Software.java
#Entity
public class Software extends Model {
#Id
private Integer id;
#OneToMany(mappedBy="software")
public List<SoftwareTag> softwareTags;
public Integer getId() {
return id;
}
public void setId(Integer aId) {
id=aId;
}
}
SoftwareTag.java
#Entity
public class SoftwareTag extends Model {
SoftwareTag() {
pk = new SoftwareTagPk();
}
#EmbeddedId
private SoftwareTagPk pk = new SoftwareTagPk();
#ManyToOne
#JoinColumn(name = "tag_id", insertable = false, updatable = false)
private Tag tag;
#ManyToOne
#JoinColumn(name = "software_id", insertable = false, updatable = false)
private Software software;
public Tag getTag() {
return tag;
}
public void setTag(Tag aTag) {
tag = aTag;
pk.tag_id = aTag.getId();
}
public Software getSoftware() {
return software;
}
public void setSoftware(Software aSoftware) {
software = aSoftware;
pk.software_id = aSoftware.getId();
}
}
SoftwareTagPk.java
#Embeddable
public class SoftwareTagPk implements Serializable {
public Integer tag_id;
public Integer software_id;
#Override
public int hashCode() {
return tag_id + software_id;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
SoftwareTagPk pk = (SoftwareTagPk)obj;
if(pk == null)
return false;
if (pk.tag_id.equals(tag_id) && pk.software_id.equals(software_id)) {
return true;
}
return false;
}
}

ClassMap to childs of abstract class

I have the following domain model to map using ClassMaps/SubclassMaps
A - HasMany -> B (A should be table)
B is abstract in code (and should not be a table)
C,D,E inherits B and all have very different properties. Each of them should be a table with foreign key to A.
I get the tables I want, but I cannot see how to map HasMany from entity A that has one property IList<B> SomeProperty
I would like to define in ClassMap<A> that SomeProperty cascades on C,D,E
This obviously doesn't work, in ClassMap<A>:
HasMany<C>(x => x.B).Cascade.All();
HasMany<D>(x => x.B).Cascade.All();
HasMany<E>(x => x.B).Cascade.All();
As I cannot duplicate B.
Example:
public class Person
{
public virtual IList<Animal> Animals { get; set; }
public void AddAnimal(Animal animal)
{
Animals.Add(animal);
}
}
public abstract class Animal
{
//some common properties
}
public class Cat : Animal
{
//some cat properties
}
public class Horse : Animal
{
//some horse properties
}
In this case I would like ClassMap<Person> to map to Cat and Horse over the abstract class Animal.
Try...
public void AddAnimal(Animal animal)
{
animal.Person = this; //Recomended
Animals.Add(animal);
}
public abstract class Animal
{
public virtual Person Person {get;set;} //Recomended Addition
//some common properties
}

How to map inheritance with property returned other inheritance?

I have abstract class Vehicle and two classes that derive from: Car and ForkLift.
public abstract class Vehicle
{
public EngineBase Engine { get; set; }
}
public class Car : Vehicle
{
public GasEngine Engine { get; set; }
}
public class ForkLift : Vehicle
{
public ElectricEngine Engine { get; set; }
}
and Engine clasess:
public abstract class EngineBase
{
}
public class GasEngine : EngineBase
{
}
public class ElectricEngine : EngineBase
{
}
Engines are mapped with "table per class hierarchy". With Vehicles I want to use the same pattern.
How to map Engine class and derived with that Engine property?
How to do it with lazy-loading?
That code does not compile, which makes it improbable that you can map it.
Use a protected field in Vehicle and map it with an access strategy:
public abstract class Vehicle
{
protected Engine _engine;
}
In Fluent NHibernate this would be mapped:
References(x => x.Engine, "EngineId").Access.CamelCaseField(Prefix.Underscore);
Then the classes that extend Vehicle can cast it as needed:
public class Car : Vehicle
{
public GasEngine
{
get { return (GasEngine)_engine; }
set { _engine = Value; }
}
}

HQL query over sub-classes

I have the following entities defined in my Entity Model:
public class MyContainer
{
public virtual ICollection<Base> Subs { get; set; }
}
public abstract class Base
{
public virtual Guid Id { get; set; }
}
public abstract class Sub1 : Base
{
public virtual int MyValue { get; set; }
}
public abstract class Sub2 : Base
{
public virtual int MyValue { get; set; }
}
and the following FluentNHibernate mappings for the above entities:
public sealed class BaseMap : ClassMap<Base>
{
public BaseMap()
{
Table("BaseTable");
Id(e => e.Id);
}
}
public sealed class Sub1Map : SubClassMap<Sub1>
{
public Sub1Map()
{
Table("Sub1Table");
KeyColumn("BaseId");
Map(e => e.Myvalue);
}
}
public sealed class Sub2Map : SubClassMap<Sub2>
{
public Sub2Map()
{
Table("Sub2Table");
KeyColumn("BaseId");
Map(e => e.Myvalue);
}
}
When I run the following HQL:
select sub
from MyContainer container
join fetch container.Subs sub
where sub.MyValue = :p1
the SQL generated only applies a constraint in the WHERE clause for one of the sub-classes, however, the generated JOINS are correct, i.e., the following skeletal SQL is generated:
SELECT ...
FROM BaseTable bt
INNER JOIN Sub1Table st1 ON ...
INNER JOIN Sub2Table st2 ON ...
WHERE st1.MyValue = #p1
where as I'm expecting an additional OR in the WHERE clause:
SELECT ...
FROM BaseTable bt
INNER JOIN Sub1Table st1 ON ...
INNER JOIN Sub2Table st2 ON ...
WHERE st1.MyValue = #p1
OR st2.MyValue = #p2
Is there something I'm missing, or is there a way to re-write the HQL so that I can reference each sub-class in the WHERE clause and apply the constraint directly (assuming that it would then generate the additional constraint in the generated SQL)?
I'm using NHibernate 3.0.0.
MyValue should be declared and mapped in Base. It is not possible to filter base class by properties that are defined in subclasses without casting to the particular class:
where (b.class = Sub1 and b.MyValue = :p1) or (b.class = Sub2 and b.MyValue = :p1)
EDIT:
Or in FNH1.2 union subclassing can be used:
public class BaseMap : ClassMap<Base>
{
public BaseMap()
{
UseUnionSubclassForInheritanceMapping();
Table("BaseTable");
Id(e => e.Id);
}
}