I'm not very deep into JPA Queries and have the current situation:
#Entity(name = "ParentElement")
#Table(name = "parent_element")
data class ParentElementData(
#Id
#GeneratedValue
val id: Long?,
#ElementCollection
var values: List<ChildElementData> = emptyList(),
)
#Entity(name = "ChildElement")
#Table(name = "child_element")
data class ChildElementData(
#Id
#GeneratedValue
val id: Long?,
#Column(nullable = false)
val attribute: Long,
)
What I would like to achieve is getting all ParentElements where ChildElement.attribute has a specific value.
So I started with the Repository
interface ParentElementRepository : CrudRepository<ParentElementData, Long> {
#Query("select p from ParentElement p where p.values ")
fun findByChildAttribute(attribute: Long): List<ParentElementData>
}
but I have no idea how to finish the query.
Had a look on that: https://github.com/odrotbohm/repositories-deepdive/blob/master/src/main/java/de/olivergierke/deepdive/ProductRepository.java but doesn't work yet.
Thx
The query will be like:
#Query("select p from ParentElement p JOIN p.values val where val.attribute = ?1 ")
fun findByChildAttribute(attribute: Long): List<ParentElementData>
As you can see, the #ElementCollection works just as the #OneToMany.
Related
In Postgre database I defined new ENUM type:
CREATE TYPE role_type as ENUM ( 'DOCTOR', 'NURSE');
In Kotlion code, I have the following definition:
enum class Role ( val roleName: String) {
Doctor("DOCTOR"),
Nurse("NURSE");
companion object {
fun getFromName(roleName: String) =
when(roleName) {
"DOCTOR" -> Doctor
else -> Nurse
}
}
}
and I defined an entity:
#Entity
#Table(name = "employees")
data class Employee(
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Int = 0,
#Column(name="first_name", length = 50)
val firstName: String,
#Column(name="last_name", length = 50)
val lastName: String,
#Column(name="is_admin")
val isAdmin: Boolean,
#Column(name="username")
val username: String,
#Column(name="role")
var role: Role,
#Column(name="password_hash", length = 128)
val passwordHash: String,
)
Also, I defined an AttributeConverter:
#Converter(autoApply = true)
class RoleConverter: AttributeConverter<Role, String> {
override fun convertToDatabaseColumn(role: Role): String = role.roleName
override fun convertToEntityAttribute(roleName: String?): Role = Role.values().first { r -> r.roleName == roleName }
}
When I try to execute the folowing line:
employeeService.saveEmployee(
Employee(firstName = "John", lastName = "Doe", isAdmin = true, passwordHash = "1234", username = "john", role = Role.Doctor)
)
, I receive the following error:
Hibernate: insert into employees (first_name, is_admin, last_name, password_hash, role, username) values (?, ?, ?, ?, ?, ?)
ERROR: column "role" is of type role_type but expression is of type character varying at character 112
HINT: You will need to rewrite or cast the expression.
How can I solve this bug?
I also tried with setting #Type and Enumerated annotations, but with no luck:
#Type(type = "role_type")
#Enumerated(EnumType.STRING)
var role: Role,
The code seems to be OK, have you tried it without auto apply annotation on converter and with direct converter specification on attribute?
#Convert(converter = RoleConverter::class)
var role: Role,
Also, have you tried debugging, if the convertToDatabaseColumn method is called on save?
I'm currently a student of FP. As I look around different syntax offer by different functional languages, I've come across a pattern in Elm sample code. I am curious about it.
Here is the sample code
myList = [{foo = "bar1"},{foo = "bar2"}]
foos = myList |> List.map .foo
In the last line here, List.map is being passed .foo. I believe this style is called point-free but what about the specific pattern of passing in an attribute to the List.map function?
Is this a more common thing? Is it possible to do this in Haskell? F#? Scala? Thanks for any help.
What is the (or is there a) formal (or informal ?) name for the pattern here? The property of an object is used as a short hand for a function that takes an object and calls said property on it?
If you think of your list as a "dataset" or "table", and consider each element in the list to be a "row", and the definition of the datatype of the elements as an enumeration of "attributes", then what you get is a kind of "projection" in the sense of relational algebra: https://en.wikipedia.org/wiki/Projection_(relational_algebra) .
Here is a Scala-example, which feels somewhat SQL-ish:
case class Row(id: Int, name: String, surname: String, age: Int)
val data = List(
Row(0, "Bob", "Smith", 25),
Row(1, "Charles", "Miller", 35),
Row(2, "Drew", "Shephard", 45),
Row(3, "Evan", "Bishop", 55)
)
val surnames = data map (_.surname)
val ages = data map (_.age)
val selectIdName = data map { row => (row.id, row.name) }
println(surnames)
// List(Smith, Miller, Shephard, Bishop)
println(selectIdName)
// List((0,Bob), (1,Charles), (2,Drew), (3,Evan))
Here, _.fieldName is a short syntax for an inline function literal of type Row => TypeOfTheField.
In Haskell, it's kind of trivial, because the declaration of a record datatype automatically brings all the getter functions into scope:
data Row = Row { id :: Int
, name :: String
, surname :: String
, age :: Int
} deriving Show
main = let dataset = [ Row 0 "Bob" "Smith" 25
, Row 1 "Charles" "Miller" 35
, Row 2 "Drew" "Shephard" 45
, Row 3 "Evan" "Bishop" 55
]
in print $ map name dataset
-- prints ["Bob","Charles","Drew","Evan"]
Even Java has something similar since version 8:
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.*;
class JavaProjectionExample {
private static class Row {
private final int id;
private final String name;
private final String surname;
private final int age;
public Row(int id, String name, String surname, int age) {
super();
this.id = id;
this.name = name;
this.surname = surname;
this.age = age;
}
public int getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getSurname() {
return this.surname;
}
public int getAge() {
return this.age;
}
}
public static void main(String[] args) {
List<Row> data = Arrays.asList(
new Row(0, "Bob", "Smith", 25),
new Row(1, "Charles", "Miller", 35),
new Row(2, "Drew", "Shephard", 45),
new Row(3, "Evan", "Bishop", 55)
);
List<Integer> ids = data.stream().map(Row::getId).collect(toList());
List<String> names = data.stream().map(Row::getName).collect(toList());
System.out.println(ids);
System.out.println(names);
}
}
Here, Row::getterName is a special syntax for getter methods, it is a value of type Function<Row, FieldType>.
This is actually not point free, but rather syntactic sugar and the pipe forward operator. For point free see this article.
This can be written in fsharp as follows:
let foos = myList |> List.map (fun x -> x.foo)
And you can see immediately that this is equivalent to
List.map (fun x -> x.foo) myList
So the pipe operator just flips the arguments and makes it easy to chain operations together. So you pass your function and a list to the map. And the syntactic sugar in Elm allows you to skip the function parameter, by just writing out .foo. I think that feature is quite handy, btw.
Point-free would be when you avoid specifying the parameters of the function. It's typical FP but can be difficult to read once it gets complicated.
An example:
let mySum x y = x + y
//val mySum : x:int -> y:int -> int
mySum 4 7 //11
This is point free:
let mySum2 = (+)
//val mySum2 : (int -> int -> int)
mySum2 4 7 //11
I have 2 databases (database1 and database2).
database1 has table1 with field id
database2 has table2 with field id
Now how do i perform leftJoin(as shown below) using Slick?
SELECT tb1.`id`
FROM `database1`.`table1` t1
LEFT JOIN `database1`.`table2` t2 ON t1.`id`=t2.`id`
I may be wrong here but most existing relational databases don't allow you to span multiple databases within single operation. However, what you showed above is easily achievable by using schema (and I strongly believe this is what you want to really achieve -judging by the SQL you pasted).
Let's have an example. Let's assume we have two tables defined within our Slick-related code as follows:
// student
case class Student(name: String,
middleName: Option[String],
surname: String,
nationality: String,
id: Id[Student] = Id.none)
class StudentTable(tag: Tag) extends Table[Student](tag, "STUDENT") {
def name = column[String]("NAME")
def middleName = column[Option[String]]("MIDDLE_NAME")
def surname = column[String]("SURNAME")
def nationality = column[String]("NATIONALITY")
def id = column[Id[Student]]("ID", O.PrimaryKey, O.AutoInc)
def * = (name, middleName, surname, nationality, id) <> (Student.tupled, Student.unapply)
}
lazy val StudentTable = TableQuery[StudentTable]
// document
case class Document(studentId: Option[Id[Student]],
name: String,
uuid: String,
id: Id[Document] = Id.none)
class DocumentTable(tag: Tag) extends Table[Document](tag, "DOCUMENT") {
def studentId = column[Option[Id[Student]]]("STUDENT_ID")
def name = column[String]("NAME")
def uuid = column[String]("UUID")
def id = column[Id[Document]]("ID", O.PrimaryKey, O.AutoInc)
def * = (studentId, name, uuid, id) <> (Document.tupled, Document.unapply)
def student = foreignKey("fk_document_student", studentId, StudentTable)(_.id.?)
}
lazy val DocumentTable = TableQuery[DocumentTable]
Doing following query:
DocumentTable
.joinLeft(StudentTable).on(_.studentId === _.id)
.filter { case(doc, student) => student.map(_.name) === "Test" }
will generate following SQL:
select x2."STUDENT_ID", x2."NAME", x2."UUID", x2."ID", x3."NAME", x3."MIDDLE_NAME", x3."SURNAME", x3."NATIONALITY", x3."ID"
from "DOCUMENT" x2
left outer join "STUDENT" x3 on x2."STUDENT_ID" = x3."ID"
where x3."NAME" = 'Test'
If I however change my table definition to:
class StudentTable(tag: Tag) extends Table[Student](tag, _schemaName = Option("database2"), "STUDENT") {
...
and this
class DocumentTable(tag: Tag) extends Table[Document](tag, _schemaName = Option("database1"), "DOCUMENT") {
...
Notice that I added one parameter - _schemaName - which indicates that particular table should be prefixed by specified schema.
I will have (same Slick query) following SQL generated now:
select x2."STUDENT_ID", x2."NAME", x2."UUID", x2."ID", x3."NAME", x3."MIDDLE_NAME", x3."SURNAME", x3."NATIONALITY", x3."ID"
from "database1"."DOCUMENT" x2
left outer join "database2"."STUDENT" x3 on x2."STUDENT_ID" = x3."ID"
where x3."NAME" = 'Test'
which seems to be precisely what you want to achieve.
I'm trying to do a simple many-to-one relationship in EF and have defined it like:
type Car() =
[<DefaultValue>] val mutable private id : int
member x.ID with get() = x.id and set(v) = x.id <- v
[<DefaultValue>] val mutable private carName : string
member x.CarName with get() = x.carName and set(v) = x.carName <- v
[<DefaultValue>] val mutable private dealer : Dealer
member x.Dealer with get() = x.dealer and set(v) = x.dealer <- v
and Dealer() =
[<DefaultValue>] val mutable private id : int
member x.ID with get() = x.id and set(v) = x.id <- v
[<DefaultValue>] val mutable private name : string
member x.Name with get() = x.name and set(v) = x.name <- v
[<DefaultValue>] val mutable private cars : seq<Car>
member x.Cars with get() = x.cars and set(v) = x.cars <- v
type MyContext() =
inherit DbContext("MyContext")
[<DefaultValue(true)>] val mutable private cars : DbSet<Car>
member x.Cars with get() = x.cars and set(v) = x.cars <- v
[<DefaultValue(true)>] val mutable private dealers : DbSet<Dealer>
member x.Dealers with get() = x.dealers and set(v) = x.dealers <- v
and calling it the following way in the console start:
let ctx = new MyContext()
Query.query <# seq { for x in ctx.Cars do if x.CarName = "Volvo" then yield x.Dealer.Name } #>
the above will generate the following SQL Query:
SELECT
[Extent2].[Name] AS [Name]
FROM [dbo].[Cars] AS [Extent1]
LEFT OUTER JOIN [dbo].[Dealers] AS [Extent2] ON [Extent1].[Dealer_ID] = [Extent2].[ID]
WHERE N'Volvo' = [Extent1].[CarName]
Now is my question, why do it take the Dealer defined in the Car type and translate it to Dealer_ID instead of DealerID?
Try specifying the explicit mapping for this property using either the StoreName DataAnnotation attribute or the Fluent mapping HasColumnName method.
looks like when scala 2.8.0 is out, we can use nested #annotations in our persistence layers. But how? Can anyone please transform this from java to scala? Thanks.
#NamedQueries({
#NamedQuery(name = "findAll", query="select p from Person p"),
#NamedQuery(name = "findTheOne",
query="select p from Person p where p.name = 'Neo'")
})
You have to wrap the elements in an Array() and write the nested annotations like a constructor call:
#NamedQueries(Array(
new NamedQuery(name = "findAll", query="select p from Person p"),
new NamedQuery(name = "findTheOne",
query="select p from Person p where p.name = 'Neo'")
))