jpa #joinColumns with a value from another joined column - jpa

I need to implement entities of 3 tables
To represent;
Table A(fields A1, A2, A4)
Table B(fields B1, B2, B3)
Table C(fields C1, C3, C4)
(This is really how they implemented and it is not even the simplest join).
A(one) -> B (many) -- B(many) -> C(one)
But to be clear, B is not an intermediary table, it represents objects (just like A and C)
On my entity class B, I have implemented A -> B like this (which is working fine)
#JoinColumns({
#JoinColumn(name = "B1", referencedColumnName = "A1"),
#JoinColumn(name = "B2", referencedColumnName = "A1"),
})
private A a;
But the problem is B -> C join uses a field from table A too. What I want to implement is something like this
#JoinColumns({
#JoinColumn(name = "B1", referencedColumnName = "C1"),
#JoinColumn(name = "B3", referencedColumnName = "C3"),
#JoinColumn(name = "A4", referencedColumnName = "C4"),
// or maybe like this
// #JoinColumn(table = "A", name = "A4", referencedColumnName = "C4"),
})
private C c;
But obviously, none of them worked. What is the implementation to join entity B to C using the value from table/entity A?

Related

Converting a data class to a #MappedEntity data class in Micronaut using Kotlin

Firstly, I'm new to micronaut and kotlin.
I'm trying to convert a data class that I receive as a request body to my API. I need to persist data from this json into a Postgres table. I wasn't able to add #field annotation to a #MappedEntity data class to validate empty fields with a message. Hence, I decided to use a normal data class to parse the request body and then create a new object of the #MappedEntity class to run the save query.
The issue:
I have a #GeneratedValue Id column in my mapped Entity class. When I try to create a new object of this class, I'm not able to leave the Id column blank.
Controller:
#Post("/contribute")
#Status(HttpStatus.CREATED)
fun processIndividualContribution(
#Valid #Body individualContributionRequestTO: IndividualContributionRequestTO
): Mono<IndividualContributionDTO>
Request Body Data CLass:
#JsonIgnoreProperties(ignoreUnknown = true)
data class IndividualContributionRequestTO(
#field: NotEmpty(message = "Transaction Id cannot be null") val transactionId: String,
#field: NotEmpty(message = "First Name can't be null") val firstName: String,
val lastName: String? = null,
#field: NotEmpty(message = "Email address can't be null") val emailAddress: String,
#field: NotEmpty(message = "Individual Contribution can't be null") val contribution: String,
)
{
fun toPurchasedDataEntity(individualContributionRequestTO: IndividualContributionRequestTO): PurchaseDataAll{
return PurchaseDataAll(
purchaserFirstName = individualContributionRequestTO.firstName,
purchaserLastName = individualContributionRequestTO.lastName,
purchaserEmail = individualContributionRequestTO.emailAddress,
contribution = individualContributionRequestTO.contribution
)
}
}
Mapped Entity Class:
#MappedEntity
#Table(name="purchased_all")
data class PurchaseDataAll (
#Id
#GeneratedValue
#Column(name = "purchase_id")
val purchaseId: Int,
#Column(name = "transaction_id")
val transactionId: String,
#Column(name = "purchaser_first_name")
val purchaserFirstName: String,
#Column(name = "purchaser_last_name")
val purchaserLastName: String? = null,
#Column(name = "purchaser_email")
val purchaserEmail: String,
#Column(name = "contribution")
val contribution: String,
#DateCreated
#Column(name = "created_ts")
var createdTs: LocalDateTime? = null,
#DateUpdated
#Column(name = "updated_ts")
var updatedTs: LocalDateTime? = null
)
The function toPurchasedDataEntity doesn't compile due to the missing purchaseId field in the returned object.
Is there a way I can parse the request body data class to the mapped entity class by ignoring the auto generated field?
In Kotlin, you'll have to prefix annotations witn field: like shown below. I also changed def for purchaseId so you don't have to specify it when mapping from view class (DTO) to entity class.
IMHO, I think it's a good approach to separate entity classes from view classes as you've done in your question.
#MappedEntity
#Table(name="purchased_all")
data class PurchaseDataAll (
#field:Id
#field:GeneratedValue
#field:Column(name = "purchase_id")
var purchaseId: Int? = null,
#field:Column(name = "transaction_id")
val transactionId: String,
#field:Column(name = "purchaser_first_name")
val purchaserFirstName: String,
#field:Column(name = "purchaser_last_name")
val purchaserLastName: String? = null,
#field:Column(name = "purchaser_email")
val purchaserEmail: String,
#field:Column(name = "contribution")
val contribution: String,
#field:DateCreated
#field:Column(name = "created_ts")
var createdTs: LocalDateTime? = null,
#field:DateUpdated
#field:Column(name = "updated_ts")
var updatedTs: LocalDateTime? = null
)

Getting Error while querying to mysql with doobie

I have transactor below
val transactor: Resource[IO, HikariTransactor[IO]] =
for {
ce <- ExecutionContexts.fixedThreadPool[IO](32) // our connect EC
be <- Blocker[IO] // our blocking EC
xa <- HikariTransactor.newHikariTransactor[IO](
"com.mysql.cj.jdbc.Driver",
"jdbc:mysql://localhost:3306/ems",
"username",
"password",
ce,
be
)
} yield xa
I am querying mysql with below code
val table = "companies"
val keyCol = "id"
val columns = List("address",
"city",
"companyname",
"email",
"mobile",
"id",
"registerdate",
"registrationexp")
val queryString =
s"""SELECT ${columns.mkString(", ")}
FROM $table WHERE $keyCol = ? """
log.debug(s"$queryString")
transactor.use { xa =>
{
Query[Int, Company](queryString).option(id).transact(xa)
}
}
Company is a case class having above column name
But getting below error
java.lang.ClassCastException: Cannot cast scala.Some to Company
where I am doing wrong
Thanks in advance

Hibernate lazy relations are fetched n+1 without properties being called - Kotlin

I am using hibernate and doing a simple query to select all of a given entity. I only want the entity and not its relations. However hibernate does fetch the relations and the relations of the relations, in a n+1 manner.
It's a Spring Boot application and written in Kotlin.
The relations are annotated with FetchType.LAZY and the query i'm doing looks like so:
entityManager.createQuery("SELECT a FROM Apartment a")
.resultList
This is the only code that i am calling and i do NOT even return the results from the controller, so it is not some serialization library that calls the lazy properties.
These are the entities:
#Entity
class Apartment(
#Id
private val id: String,
private val heading: String,
#ManyToOne(fetch = LAZY)
private val building: Building
)
#Entity
class Building(
#Id
private val id: String,
private val heading: String,
#ManyToOne(fetch = FetchType.LAZY)
private val owner: User
)
#Entity
#Table(name="users")
class User(
#Id
private val id: String,
private val email: String
)
I have turned on hibernate query logging, and when i run the query above it looks like:
Fetch all apartments
Fetch buildings for apartment 1
Fetch users for building 1
fetch buildings for apartment 2
fetch users for building 2
....
I have created a git repository that reproduces the problem: https://github.com/Herlevsen/hibernate-lazy-fetch-repoduction
It comes setup with a docker-compose file that launches a postgres database, and the application automatically creates the schema and creates some dummy data on startup. So it's fairly easy to get up and running.
I'm really hoping someone can tell me what's going on.
Thanks!
You have to open the entity classes. Hibernate requires open classes to create proxies to support LAZY - ManyToOne fields:
#Entity
open class Apartment(
#Id
private val id: String,
private val heading: String,
#ManyToOne(fetch = LAZY)
private val building: Building
)
#Entity
open class Building(
#Id
private val id: String,
private val heading: String,
#ManyToOne(fetch = FetchType.LAZY)
private val owner: User
)
#Entity
#Table(name="users")
open class User(
#Id
private val id: String,
private val email: String
)
You can also use the all-open-Plugin.

Sorting by list in Scala

I lately encountered this question: JPA: How do I sort on a Set field in my entity?
I started to think how similar sorting can be done in Scala.
So we have a list of users. Every user has sorted list of organizations. And we want to sort this list of users by list of organization names. Users are sorted by first organization name and when first names are equal then they are compared by second names and so on.
I have managed to write such sorting but in some cases it is giving wrong result.
class Organization (aId: Int, aName: String) {
val id:Int = aId
var name:String = aName
}
class User (aId: Int, aOrganizations: List[Organization]) {
val id:Int = aId
var organizations:List[Organization] = aOrganizations
}
val o1 = new Organization(1, "AAA")
val o2 = new Organization(2, "AAAA")
val o3 = new Organization(3, "BBB")
val o4 = new Organization(4, "BBBB")
val o5 = new Organization(5, "CCC")
val o6 = new Organization(6, "AAA BBB")
val u1 = new User(1, List(o1))
val u2 = new User(2, List(o2))
val u3 = new User(3, List(o3))
val u4 = new User(4, List(o4))
val u5 = new User(5, List(o1,o5))
val u6 = new User(6, List(o2,o3))
val u7 = new User(7, List(o3,o4))
val u8 = new User(8, List(o1,o2,o3,o4))
val u9 = new User(9, List(o1,o2,o3,o5))
val u10 = new User(10, List())
val u11 = new User(11, List(o6))
val users = List(u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11)
// below line should be improved
val sortedUsers = users.sortWith(_.organizations.foldLeft("")((b,a) => b + a.name + ",") < _.organizations.foldLeft("")((b,a) => b + a.name + ","))
sortedUsers.foreach{ x => print(x.id+" ")}
// received result: 10 11 1 8 9 5 2 6 3 7 4
// expected result: 10 1 8 9 5 11 2 6 3 7 4
How can such sorting be done?
The most straightforward way to solve this is probably to use sortBy instead of sortWith. Scala provides a lexicographic ordering instance for Iterable[A] where A has an ordering instance, so you just need to provide an ordering instance for Organization:
implicit val organizationOrdering: Ordering[Organization] =
Ordering.by(_.name)
val sortedUsers = users.sortBy(_.organizations.toIterable)
You could also just provide an instance for User and then use sorted:
implicit val organizationOrdering: Ordering[Organization] =
Ordering.by(_.name)
implicit val userOrdering: Ordering[User] =
Ordering.by(_.organizations.toIterable)
val sortedUsers = users.sorted
If you don't want to introduce these instances, you can pass the one you need explicitly:
val sortedUsers = users.sortBy(_.organizations.toIterable)(
Ordering.Iterable(Ordering.by(_.name))
)
It's a shame that there's not an instance for List[A: Ordering], but there are apparently good reasons for that.

Using scala constants in constant expressions

I have constants, that are made of other, smaller constants. For example
object MyConstants {
final val TABLENAME = "table_name";
final val FIELDNAME = "field_name";
final val INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix"; // this one does not want to be constant
}
I want these to be true constants because I use them in annotations.
How do I make it work? (on scala 2.11)
What I want is
interface MyConstants {
String TABLENAME = "table_name";
String FIELDNAME = "field_name";
String INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix";
}
but in scala. Scalac does not pick up constants for usage in annotations if it compiles them from java class/interface (see SI-5333) so I decided to put them in a scala object. It works for literals, and for expressions with literals, but not for expressions with other constants.
With this code:
import javax.persistence.Entity
import javax.persistence.Table
import org.hibernate.annotations.Index
object MyConstants {
final val TABLENAME = "table_name";
final val FIELDNAME = "field_name";
final val INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix";
}
#Entity
#Table(name = MyConstants.TABLENAME)
#org.hibernate.annotations.Table(
appliesTo = MyConstants.TABLENAME,
indexes = Array(new Index(name = MyConstants.INDEXNAME, columnNames = Array(MyConstants.FIELDNAME))))
class MyEntity {
}
I get a following error on line indexes = ...
annotation argument needs to be a constant; found: MyConstants.INDEXNAME
Edit:
After fiddling around with a few build configurations, I think this is actually a scala-ide specific issue. The code does indeed compile alright when I build project with gradle or sbt. I do use build tool for my actual projects, so in the end it's about having a few incomprehensible markers in the IDE - annoying, but has little to do with functionality.
I used constants in JPA with scala. This code compiles, and I used it:
FreeDays.scala
#Entity
#Table(name = "free_days")
#NamedQueries(
Array(
new NamedQuery(name = JpaQueries.IS_FREE_DAYS, query = "SELECT f FROM FreeDays f WHERE f.dateOfFreeDay = :" + JpaQueries.DATE)
)
)
class FreeDays {
def this(id: Int, name: String, dateOfFreeDay: Date) = {
this()
this.id = id
this.name = name
this.dateOfFreeDay = dateOfFreeDay
}
#Id
#GeneratedValue
var id: Long = _
var name: String = _
#Column(name = "date_of_free_day")
#Temporal(TemporalType.DATE)
var dateOfFreeDay: Date = _
}
JpaQueries.scala
object JpaQueries extends JpaQueries
sealed trait JpaQueries {
final val IS_FREE_DAYS = "IS_FREE_DAYS"
final val DATE = "date"
}