How to populate a collection inside a DAO object using MyBatis annotaions (or even without it)? - sql

I have a DAO User :
class User{
int id,
int name,
List<Vehicle> vehicles;
}
In my UserMapper.java interface, I have a method that gives me User DAO :
#Select("select u.id, u.name, v.id, v.name from User u, Vehicle v where u.id=#{id} and v.user_id=u.id")
public User getUser(int id);
How to make sure that the above query fills the User object's vehicle collection properly ?
Please use annotations (and XML only as a last resort)

From Mybatis 3 User Guide,
Note: You will notice that join mapping is not supported via the Annotations
API. This is due to the limitation in Java Annotations that does not
allow for circular references.
Best you can do is something like this,
#Results({
#Result(property = "id", column = "id", id = true),
#Result(property = "name", column = "name"),
#Result(many=#Many(select="your select"), javaType=Vehicle.class)
})
#Select("select u.id, u.name, v.id, v.name from User u, Vehicle v where u.id=#{id} and v.user_id=u.id")
public User getUser(int id);
My advice, use the xml.

Related

What is the best way to go about referencing multiple tables using slick 2.0?

I have these tables: USERS, USER_ROLES, ROLES, PERMISSIONS, ROLE_PERMISSIONS
I am implementing the:
AssignedRoles (M): returns the set of roles assigned to a given user;
So, if I was going to write the query for this function it would like something like this:
SELECT role_id FROM USER_ROLES WHERE user_id = 'M'
where M is the given user id, then I would look up each role by their id and return the Role object, or I would use a join, but that is not relevant here.
so where is what my UserRole model looks like:
case class UserRole(id:Long, userID:Long, roleID:Long)
object UserRoles {
class UserRoles(tag: Tag) extends Table[UserRole](tag, "USER_ROLES") {
def id = column[Long]("ID", O.PrimaryKey, O.AutoInc)
def userID = column[Long]("USER_ID")
def roleID = column[Long]("ROLE_ID")
def user = foreignKey("USER_ID", userID, TableQuery[Users])(_.id)
def role = foreignKey("ROLE_ID", roleID, TableQuery[Roles])(_.id)
def * = (id, userID, roleID) <> (UserRole.tupled, UserRole.unapply)
}
def retrieveRoles(userID:Long) : List[Role] = {
DB.withSession { implicit session =>
userRoles.filter(_.userID === userID).list
}
}
As expected retrieveRoles returns a list of UserRoles, but I want a list of Roles, so I woulds have to write another query that will take UserRole.roleID and find it in the roles table for each of UserRole that is returned. That is a lot of queries and I feel like there is a way that will to do this in one query. Any help from the Slick experts?
userRoles.filter(_.userID === userID).flatMap(_.role)

JasperReports for grails: Using HashMap as Model?

Imagine I have two classes in Groovy that look like that:
class Person {
int id;
String name;
}
class Item {
int id;
int price;
}
Now it would be simple to create a JasperReport listing all persons' names using the following SQL:
SELECT name FROM Person
Also, it would be easy to pass a Model from which the list should be created:
def p = Person.withCriteria {
eq('name','SomeGuy')
}
chain(controller:'jasper',action:'index',model:[data:p],params:params)
But what I want to do is to use the following query:
SELECT name, (SELECT sum(i.price) FROM Item f WHERE f.id=p.id) as priceSum FROM Person p
And now this is the part where I don't know how to go on: How can I pass any Model to the jasperReport? I can't just use
def p = Person.withCriteria {
eq('name','SomeGuy')
}
because then, the priceSum attribute would be missing.
What I would like to do is something like this:
def l = ['name':'SomeGuy','priceSum':'5000']
chain(controller:'jasper',action:'index',model:[data:l],params:params)
But this doesn't work either, it gives me:
Message: Cannot get property 'name' on null object
Caused by: java.lang.NullPointerException: Cannot get property 'name' on null object
Is there anything simliar to this that would work?

Symfony2 + Doctrine - Filtering

I've got a OneToMany relationship where one football team has many players. I want to list all football teams and display the name of the captain for each team.
Each player entity has a foreign key (team_id) and a field 'captain' which is set to 0 or 1. I'm currently running the following query:
$teams = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()->getResult();
Then when I loop through each team in twig I run team.getTeamCaptain().getName() which is a filter within my Team entity:
public function getTeamCaptain() {
$them = $this->players->filter(function($p) {
return $p->getCaptain() == 1;
});
return $them->first();
}
Is there a better way to run this query?
First of all, you may want to fetch-join the players of each retrieved team to avoid having them lazy loaded during rendering of the template. Here's the DQL:
SELECT
t, p
FROM
FootballWebsiteBundle:Team t
LEFT JOIN
t.players p
WHERE
t.deleted = 0
ORDER BY
t.name DESC
Which can be built with following query builder API calls:
$teamsQuery = $this
->getDoctrine()
->getRepository('FootballWebsiteBundle:Team')
->createQueryBuilder('t')
->addSelect('p')
->leftJoin('t.players', 'p')
->add('where','t.deleted = 0')
->add('orderBy', 't.name DESC')
->getQuery()
Then you wrap this query into a Paginator object (since setMaxResults and setFirstResult cannot be trusted when fetch-joining):
$paginator = new \Doctrine\ORM\Tools\Pagination\Paginator($teamsQuery, true);
$teamsQuery
->setFirstResult(($pageNumber * $resultPerPage) - $resultPerPage)
->setMaxResults($resultPerPage)
In your view you can then iterate on the teams like following pseudo-code:
foreach ($paginator as $team) {
echo $team->getTeamCaptain() . "\n";
}
You can also gain some extra performance in your getTeamCaptain method by using the Selectable API:
public function getTeamCaptain() {
$criteria = new \Doctrine\Common\Collections\Criteria();
$criteria->andWhere($criteria->expr()->eq('captain', 1));
return $this->players->matching($criteria)->first();
}
The advantage here is mainly relevant when the association players is not yet initialized, since this will avoid loading it entirely. This is not the case, but I consider it a good practice (instead of re-inventing collection filtering logic).

Grails criteria groupby object

Example grouping by name of the zones:
def result = User.createCriteria().list{
projections {
roles {
zones{
groupProperty("name")
}
}
}
}
but suppose I want to get the "id" or other attributes. the fact is that i want the object on the representing the group and not the string "name".
result.each{ println it.customFuncion() }
"zones" is a hasMany attribute and then i cant group by itself. What should be done, but doesnt works:
def result = User.createCriteria().list{
projections {
roles {
groupProperty("zones")
}
}
}
Is that possible? Thank you guys!
use hql for complex queries:
def result = User.executeQuery("select u.id, zone.name from User as u inner join u.roles as role inner join role.zones as zone group by u.id, zone.name")
Then you can access the result columns as follows:
result.each { row -> row[0] // u.id } // or access via defined column name
Imagine that i do not know your real hasMany collection names.

NHibernate Polymorphic Query on a Collection

I'm trying to write a query in NHibernate. I don't really care if I use the Criteria API or HQL, I just can't figure out how to write the query.
Here's my model:
public class LogEntry { public DateTime TimeCreated { get; set; } }
public class Note : LogEntry { public string Content { get; set; } }
public class Workflow { public IList<LogEntry> Log { get; set; } }
I want the query to return all Workflows that which contain a Note with specific words in the Content of the note.
In pseudo-SQL, I'd write this like:
select w.*
from Workflow w
join w.Log l where l is class:Note
where (Note)l.Content like '%keyword%'
I'm not sure about the Criteria API, but HQL seems to handle polymorphic queries quite well, even when searching on a property that only exists in a specific sub-class. I would expect the following to work:
from Workflow w join w.Log l where l.class = Note and l.Content like '%keyword%'
I don't know if there is a better way, but I use subqueries for this:
from Workflow w
join w.Log l
where l in (
select n
from Note n
where n.Content like '%keyword%'
)
(if this doesn't work, write l.id in (select n.id...)
In criteria, you can directly filter properties that are only available on a subclass, but you shouldn't, because it only filters for the first subtype it finds where this property is defined.
I use subqueries as well:
DetachedCriteria subquery = DetachedCriteria.For<Note>("n")
.Add(Expression.Like("n.Content", "%keyword%"))
.SetProjection(Projections.Property("n.id"));
IList<Workflow> workflows = session.CreateCriteria<Workflow>("w")
.CreateCriteria("w.Log", "l")
.Add(Subqueries.PropertyIn("l.id", subquery))
.List<Workflow>();