How do a Criteria polymorphic join in JPA? - jpa

I have a project that have a modeling like this:
public abstract class Actor{}
public class Person extends Actor {}
public class Organization extends Actor {}
public abstract class Role{ #ManyToOne #JoinColumn(name="ID_ACTOR") }
public class Customer extends Role{}
public class Employee extends Role{}
I would like to get a List<Role> which plays a particular Actor:
public List<Role> getRoles(Actor actor) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Role> criteria = builder.createQuery(Role.class);
//How to do this filter using Criteria API (JPA 2.1)?
return query.getResultList();
}
The SQL below makes the job:
SELECT 'Customer' as role, c.id as id, c.id_actor as actor
FROM customer c
left join person p on p.id = c.id_actor
left join organization o on o.id = c.id_actor
where c.id_actor = ?
UNION
SELECT 'Employee' as role, e.id as id, e.id_actor as actor
FROM employee e
left join person p on p.id = e.id_actor
left join organization o on o.id = e.id_actor
where e.id_actor = ?

I resolve the problem making a bidirectional relationship between Actor and Role class:
public abstract class Actor{ #OneToMany(mappedBy="actor") List<Role> roles }
public class Person extends Actor {}
public class Organization extends Actor {}
public abstract class Role{ #ManyToOne #JoinColumn(name="ID_ACTOR") Actor actor }
public class Customer extends Role{}
public class Employee extends Role{}
That way I could get the List<role> which plays a particular Actor:
public List<Role> getRoles(Actor actor) {
return actor.getRoles();
}
Initially I would like to avoid the bidirectional relationship, but I realized that in this particular case, there are direct benefits

Related

MapStruct: How to specify in mapper the type of objects should be created in the destination List?

In Dozer the mapping between domain and DTO classes is done as following:
<mapping>
<class-a>Domain.A</class-a>
<class-b>DTO.A</class-b>
<field>
<a>cField</a>
<b>cField</b>
<a-hint>Domain.Ab</a-hint>
<b-hint>DTO.Ab</b-hint>
</field>
</mapping>
hint is used to let dozer know what type of objects you want created in the destination List(Correct me if I'm wrong).
How can we achieve the same in MapStruct?
Where, the implementation of class A is as following:
public class A<T extends Ab> extends B<T>{
}
Implementation of B is as following:
public class B<T extends C> implements serializable{
private List<T> cField = new ArrayList<T>();
private String d;
//getters and setters
}
Implementation of Ab is as following:
public abstract class Ab implements C{
}
Here C is an interface with no fields in it.
There are no fields in Ab and is extended by some E and F classes.
Could you please let me know how would the mapper look like for the above scenario ?

Kotlin JPA Inheritance advise

What I want is to have two user types that inherit from one user super class. When I'm authenticating a user through username/password I don't care who they are at that point. However once they start making requests once logged in it will become important then.
I don't know what I should be using for the inheritance type and the repositories in kotlin for this.
#MappedSuperClass
open class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val Id: Long = 0
val username:String = ""
val password:String = ""
}
type1
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
data class Type1(
val property1: String) : User
{
val property2: String = ""
}
type2
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
data class Type2(
val property1: String) : User
{
val property2: String = ""
}
What I'd like to have is a user repository to be able to look at user name and password, and then repositories for the other two to get the specific properties of each. I tried
#Repository
interface UserRepository: JpaRepository<User, Long> {
fun getUserByUsername(username: String)
}
and then
#Repository
interface Type1Repository: UserRepository<Type1, Long>
but it wouldn't accept the <> in the type 1 repository.
I haven't found a good resource talking about this for kotlin yet. If you know of one please pass it along. Thanks.
Like shown in here: https://ideone.com/JmqsDn you are just missing the types in your intermediate interface, ie.:
interface UserRepository<User, Long>: JpaRepository<User, Long> {
fun getUserByUsername(username: String)
}
Side note: kotlin 1.1+ is required for data classes to inherit from other classes.

JPA annotation that will include fields from non-entity super class (from JAR!)

I am working with spring boot, spring JPA and have following problem: I created some class "B" that extends some class "A" from JAR, put #Entity and #Table annotations on class "B" (I can't do the same on class "A") but when Spring/Hibernate is creating tables, only fields from class "B" are included.
// some class from JAR
// not an Entity
class A {
String fieldA;
}
#Entity
#Table(name = "B")
class B extends A {
String fieldB;
}
Table that is created in database
+--------+ +--------+--------+
| fieldB | but I want this to be made | fieldA | fieldB |
+--------+ +--------+--------+
How to manage that? Is there some JPA annotation that could be put on class B that would solve this?
EDIT: If #AttributeOverride annotation is the solution, how to mark that overriden field as Id when #Id annotation can't be put outside the class?
You can set the #Id on a getter.
#Entity
#Table(name = "B")
class B extends A {
String fieldB;
#Id
#Override
public String getFieldA() {
return super.getFieldA();
}
}

Eclipselink class extractor

I have 2 entities object A and B. B extended A and I have #ClassExtractor on A to return the correct class type from the database row. However, if I want to query on A, will it check for class extractor?
A.java
#Entity
#Table
#ClassExtractor(MyClassExtractor.class)
public class A implements Serializable{
...
}
B.java
#Entity
#Table
public class A extends B{
...
}
MyClassExtractor.java
public class MyClassExtractor extends ClassExtractor{
#SuppressWarnings("rawtypes")
#Override
public Class extractClassFromRow(Record record, Session session){
return B.class;
}
So when I do query on A, will it go to the class extractor and return B?
Thanks in advance!

How to retrieve data from many to many relationship with Lift

Let say I have 3 tables: Book, Author and BookAuthor.
Book has id, title
Author has id, name
BookAuthor has id, book_id, author_id
I want to find all authors of a book. Can anyone guide me how to do this with Lifts mapper syntax?
class Book extends LongKeyedMapper[Book]
with IdPK
with ManyToMany {
def getSingleton = Book
object title extends MappedString(this, 255)
object authors extends MappedManyToMany(
BookAuthors, BookAuthors.book, BookAuthors.author, Author)
}
object Book extends Book with LongKeyedMetaMapper[Book]
class Author extends LongKeyedMapper[Author]
with CreatedUpdated with IdPK
with ManyToMany {
def getSingleton = Author
object firstName extends MappedString(this, 255)
object lastName extends MappedText(this)
object email extends MappedEmail(this, 150)
object books extends MappedManyToMany( BookAuthors,
BookAuthors.author, BookAuthors.book, Book)
}
object Author extends Author with LongKeyedMetaMapper[Author]
val warandpeace = Book.create.title("War and Peace").saveMe
val fred = Author.create.firstName("Fred").saveMe
fred.books += warandpeace
fred.saveMe
val bob = Author.create.firstName("Bob").saveMe
bob.books += warandpeace
bob.saveMe
// then to find all the authors of the book:
val authors = warandpeace.authors
Here is the mapper for the book:
class Book extends LongKeyedMapper[Book] with IdPk with OneToMany[Long, Book] {
def getSingleton = Book
object title extends MappedString(this, 200)
object BookAuthor extends MappedOneToMany(BookAuthor, BookAuthor.id)
}
object Book extends Book with LongKeyedMetaMapper[Book]
The trait IdPk will take care of the id of Book. Then for BookAuthor:
class BookAuthor extends LongKeyedMapper[BookAuthor] with IdPk with OneToOne[Long, BookAuthor] {
def getSingleton = BookAuthor
object Author extends MappedOneToOne(Author, Author.id)
}
object BookAuthor extends BookAuthor with LongKeyedMetaMapper[BookAuthor]
Then for Author, a simple mapper:
class Author extends LongKeyedMapper[Author] with IdPk {
def getSingleton = Author
object name extends MappedString(this, 200)
}
object Author extends Author with LongKeyedMetaMapper[Author]
Then the call to find all authors of a book (here myBook ):
myBook.BookAuthor.map(x => x.Author.name)
If you want to make more complicated join requests without having to filter everything in Scala, you can always use DB and you can always find more info about mapper here.