how to use new scala 2.8.0 nested annotations - scala

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'")
))

Related

EF Core aggregation query

I use EF Core 5 and this query throws an exception. Id and EntityId are uniqueidentifiers in both tables.
query:
var records = await (from r in _dbContext.Set<MedicalRecord>()
join d in _dbContext.Set<Document>()
on r.Id equals d.EntityId into grouping
select new { r, DocumentCount = grouping.Count() }).ToListAsync();
here is an exception:
System.InvalidOperationException: The LINQ expression 'DbSet<MedicalRecord>()
.GroupJoin(
inner: DbSet<Document>(),
outerKeySelector: r => r.Id,
innerKeySelector: d => d.EntityId,
resultSelector: (r, grouping) => new {
r = r,
DocumentCount = grouping
.AsQueryable()
.Count()
})' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
Thank you

Select element by object attribute in element collection

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.

Group by in many-to-many join with Quill

I am trying to achieve with Quill what the following PostgreSQL query does:
select books.*, array_agg(authors.name) from books
join authors_books on(books.id = authors_books.book_id)
join authors on(authors.id = authors_books.author_id)
group by books.id
For now I have this in my Quill version:
val books = quote(querySchema[Book]("books"))
val authorsBooks = quote(querySchema[AuthorBook]("authors_books"))
val authors = quote(querySchema[Author]("authors"))
val q: db.Quoted[db.Query[(db.Query[Book], Seq[String])]] = quote{
books
.join(authorsBooks).on(_.id == _.book_id)
.join(authors).on(_._2.author_id == _.id)
.groupBy(_._1._1.id)
.map {
case (bId, q) => {
(q.map(_._1._1), unquote(q.map(_._2.name).arrayAgg))
}
}
}
How can I get rid of the nested query in the result (db.Query[Book]) and get a Book instead?
I might be a little bit rusty with SQL but are you sure that your query is valid? Particularly I find suspicious that you do select books.* while group by books.id i.e. you directly return fields that you didn't group by. And attempt to translate that wrong query directly is what makes things go wrong
One way to fix it is to do group by by all fields. Assuming Book is declared as:
case class Book(id: Int, name: String)
you can do
val qq: db.Quoted[db.Query[((Index, String), Seq[String])]] = quote {
books
.join(authorsBooks).on(_.id == _.book_id)
.join(authors).on(_._2.author_id == _.id)
.groupBy(r => (r._1._1.id, r._1._1.name))
.map {
case (bId, q) => {
// (Book.tupled(bId), unquote(q.map(_._2.name).arrayAgg)) // doesn't work
(bId, unquote(q.map(_._2.name).arrayAgg))
}
}
}
val res = db.run(qq).map(r => (Book.tupled(r._1), r._2))
Unfortunately it seems that you can't apply Book.tupled inside quote because you get error
The monad composition can't be expressed using applicative joins
but you can easily do it after db.run call to get back your Book.
Another option is to do group by just Book.id and then join the Book table again to get all the fields back. This might be actually cleaner and faster if there are many fields inside Book

EF code How to use lambda expresssion to implement left join?

Sql:
select a.id, b.name
from a
left join b on a.id = b.id
I want to use lambda in EF to get the same result in this sql
Here is what I've done:
var list = entities.a
.GroupJoin(
entities.b,
a => a.id,
b => b.id,
(a, b) => new { a, b })
.Select(o => o)
.ToList();
Here Select(o => o), I just don't know how to get the same result in sql
select a.id, b.name
I think this article from MSDN would be a lot helpful...
http://msdn.microsoft.com/en-us/library/bb397895.aspx
This is a quote from above article, that might help...
var query = from person in people
join pet in pets on person equals pet.Owner into gj
from subpet in gj.DefaultIfEmpty()
select new { person.FirstName, PetName = (subpet == null ? String.Empty : subpet.Name) };
UPDATE:
As per your request, the Lambda Expression would be something like this...
.SelectMany(#a => #a.#a.b.DefaultIfEmpty(), (#a, joineda) => new {#a, joineda})
Not sure, if it is correct, but it is a starting point, at least...

F# -> EF generating wrong sql

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.