I have a School table and Classroom table which has foreign key to School table. I want to get classrooms that capaties are 40 and school name is "example". Here is my generic getAll method. I want to modify this method to join 2 tables. The problem is the method still must remains generic.
public <T> List<T> getAll(T genericEntity) {
Criteria criteria = getCurrentSession().createCriteria(genericEntity.getClass());
criteria.add(Example.create(genericEntity));
return criteria.list();
}
You should add both objects to the parameter list:
public <T,U> List<T> getAll(T genericEntity1, U genericEntity2) {
Criteria criteria = getCurrentSession()
.createCriteria(genericEntity1.getClass()).add(Example.create(genericEntity1))
.createCriteria(genericEntity2.getClass()).add(Example.create(genericEntity2));
return criteria.list();
}
You can call it the following way:
getAll(classroom, school);
Related
Actually I'm confused for the case, which relation fits best for my case, and in my opinion the best one is to have a table with 3 primary keys.
To be more specific.
I have a Person model in one of my db's, which has structure like
Person:
Id,
FirstName,
LastName,
...
And the other model Department, which has structure mentioned below
Department:
Id,
Name,
Description,
...
And goal is to set up Editors of schedule for each department and add also admins, whioch will approve requested schedules from editors. Editors and Admins are from same Person table, and if to assume, we need to map some Persons and department with some type.
I'm thinking about to have a mapping table with structure
PersonID,
DepartmentID,
Type (editor or admin)
And not sure, which relation fits best for this. If to have belongsToMany relation here with primary keys PersonID and DepartmentID, we will face an issue, because same Person possibly can be as editor and as admin for one single department. I have MS SQL server as a db.
Any suggestions will be appreciated
you can define many to many relations and use wherePivot method to select by pivot table Type column:
// Department model
public function admins()
{
return $this->belongsToMany(Person::class)->wherePivot('type', 'admin');
}
public function editors()
{
return $this->belongsToMany(Person::class)->wherePivot('type', 'editor');
}
// Person model
public function departmentsWhereIsAdmin()
{
return $this->belongsToMany(Department::class)->wherePivot('type', 'admin');
}
public function departmentsWhereIsEditor()
{
return $this->belongsToMany(Department::class)->wherePivot('type', 'editor');
}
// Note: we use methods names without parentheses
// usage for department
$department = Department::first(); // for example
dump($department->admins);
dump($department->editors);
// usage for person
$person = Person::first(); // for example
dump($person->departmentsWhereIsAdmin);
dump($person->departmentsWhereIsEditor);
i have relationship many to many table 'admins' , 'pjt_roles' with pjt_role_admin.
but,not working
i have 2 model
class Role
protected $table = 'pjt_roles';
public function Admin(){
return $this->belongsToMany(Admin::class',pjt_role_admin');
}
class Admin
public function Role(){
return $this->belongsToMany(Role::class,'pjt_role_admin');
}
and table pjt_role_admin have attribute
admin_id from table admins
role_id from table pjt_roles
Specify your pivot table in relationship. Default laravel assume admin_role as your pivot table because you have Admin and Role models
class Role
protected $table = 'pjt_roles';
public function Admin(){ // should be admins() for better readability
return $this->belongsToMany(Admin::class, 'pjt_role_admin');
}
class Admin
public function Role(){ // should be roles() for better readability
return $this->belongsToMany(Role::class, 'pjt_role_admin');
}
To determine the table name of the
relationship's joining table, Eloquent will join the two related model
names in alphabetical order. However, you are free to override this
convention. You may do so by passing a second argument to the
belongsToMany method.
Fetch Data
$admin = Admin::find(1);
$roles = $admin->Role; // should change to roles() in relationship for better readability
Save
$admin->Role()->attach($roleId);
details https://laravel.com/docs/5.4/eloquent-relationships#many-to-many
Can anyone give me the equivalent Hibernate query for the MySQL query given below. I am not trying it from past few day but no success.
This is MySql query
SELECT * FROM product WHERE category_id IN (SELECT id FROM category WHERE parent_category_id IN (SELECT id FROM category WHERE parent_category_id=53));
The Hibernate query which i had written is.
public List<Product> findBy2ndLevel(String categoryName) {
Query query = null;
StringBuilder hql = new StringBuilder();
try {
hql.append("from Product product where product.category.id in");
hql.append("(select id from Category category where category.parentCategory.id in");
hql.append("(select id from Category category where category.parentCategory.id=:category_id))");
query = sessionFactory.getCurrentSession().createQuery(hql.toString());
query.setParameter("category_id",Integer.parseInt(categoryName));
} catch (HibernateException e) {
e.printStackTrace();
}
return query.list();
}
It is not working though. Give anyone correct or give me the equivalent HQ.
I'm assuming that the entity Product has 1 category and a variable for this (called category), and that a category has 1 parent category and a variable for this (called parent).
But, something like:
select p
from Product p join p.category c join c.parent pc
where pc.id = :categoryId
Furthermore, I don't really get your variable use, you link the id of category with categoryName, and include a variable orgaId which is never really used for anything.. Also, your code will produce a NullPointerException if the creation of the query fails.
I'm working with an Nhibernate Query where I have to do some complex queryover join aliases to eagerly load the children of my root entity. When loading, I want to filter the root entity results returned by a number of properties, including some which are on the children.
I've got this all working fine using joinaliases, but where I'm stumped is filtering the results returned down to the top "X" instances of the root entity when ordered by a property other than the root entities Id. Since I'm grabbing children, there are a number of duplicate rows returned by the SQL. If I try to filter the number of results with a .Take, the take executes before NHibernate collapses the result set down to the distinct root entities. For reference here's my domain model.
public class Project{
public int Id {get;set;}
public double Value {get;set;}
public IList<ProjectRole> Team {get;set;}
}
public class ProjectRole{
public User User {get;set;}
public Role Role {get;set;}
}
public class User{
public string LoginName {get;set;}
}
So I'm trying to grab all the projects where a User with the given LoginName is on the Project's Team. Then I want to order by the Project's value. I want to do this as efficiently as possible, without select n+1's etc.
What does this community recommend?
Additional Information:
As a stopgap, I'm currently returning all the results and then taking the top X in memory, but I don't want that to be permanent, because the query can return close to 10,0000 items, and I only want to top 7 or so. If I was writing straight SQL I'd just do something like this.
SELECT *
FROM Projects as p1
INNER JOIN (
SELECT distinct TOP (7)
topProjects.PGISourceItem_id as topsId,
topProjects.Value as topsValue
FROM Projects topProjects
left outer join ProjectRoles roles on topProjects.Id=roles.Project_id
left outer join PGUsers users on roles.User_id=users.Id
WHERE
(users.LoginName like 'DEV\APPROVER' or this_0_1_.IsPrivate = 0)
ORDER BY topProjects.Value desc
) as p2 on p1.Id = p2.topsId
But I can't figure out how to do this with NHibernate. The only subqueries I can create are either WHERE EXISTS or WHERE IN. And since I'm doing an ORDER BY Value I can't use WHERE IN because my select returns multiple properties.
if users have under 1k projects this might work
var subquery = QueryOver.Of<User>()
.Where(...)
.JoinAlias(x => x.Projects, () => proj)
.Select(Projections.Distinct(Projections.Property(() => proj.Id)));
session.QueryOver<Foo>()
.WithSubquery.WhereProperty(x => x.Id).In(subquery)
.Fetch(p => p.Collection)
.OrderBy(x => x.Value)
.Take(5)
.List();
Relatively new to JPA, so I have one kind of architectural question.
Let's say I have tables EMPLOYEE and DEPARTMENT with many to one relationship (i.e. many employees work for one department):
EMPLOYEE
EMPLOYEE_ID
EMPLOYEE_NAME
DEPARTMENT_ID
DEPARTMENT
DEPARTMENT_ID
DEPARTMENT_NAME
So I can define proper entities for Employee and Department, there's no problem. However, in one view I would like to display list of departments with number of employees working for that department, something like this:
SELECT D.DEPARTMENT_NAME,
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) NUMBER_OF_EMPLOYEES
FROM DEPARTMENT D
I'm just not sure what is the right strategy to accomplish this using JPA...
I don't want to always fetch number of employees for Department entity, as there is only one view when it is needed.
It looks like Hibernate's #Formula would be one possible approach, but afaik it does not conform with JPA standard.
You can create any object in your QL using the "new" syntax - your class just needs a constructor that takes the values returned by your query.
For example, with a class like DepartmentEmployeeCount, with a constructor:
public DepartmentEmployeeCount(String departmentName, Integer employeeCount)
you could use QL something like:
SELECT NEW DepartmentEmployeeCount(D.DEPARTMENT_NAME, count(E.id)) from Department D left join D.employees E GROUP BY D.DEPARTMENT_NAME
Or if you were just selecting the count(*) you could simply cast the query result to a Number.
Alternatively, to do the same without the DepartmentEmployeeCount class, you could leave out the NEW, so:
SELECT D.DEPARTMENT_NAME, count(E.id)
This would return a List<Object[]> where each list item was an array of 2 elements, departmentName and count.
To answer your later question in the comments, to populate all fields of a Department plus a transient employeeCount field, one suggestion would be to do 2 queries. This would still be more efficient than your original query (a subselect for each employee count).
So one query to read the departments
SELECT D from Department D
giving you a List<Department>
Then a 2nd query returning a temporary array:
SELECT D.DEPARTMENT_ID, count(E.id) from Department D left join D.employees E GROUP BY D.DEPARTMENT_ID
giving you a List<Object[]> with DEPARTMENT_ID and count in it.
Then you use the 2nd list to update the transient count property on your first list.
(You could try selecting into a Map to make this lookup easier, but I think that's a Hibernate feature).
Option 1: I suggested this since you didn't like the constructor route MattR was suggesting. You mentioned the word "view" several times, and I know you were talking about the view to the user, but why not setup a view in your database that includes the computed columns and then create a read-only entity that maps to the computed columns?
Option 2: In response to your comment about not wanting to create a view. You could create a container object that holds the entity and the calculated column, then much like MattR suggests, you use a new in your select. Something like:
public class DepartmentInfo {
private Department department;
// this might have to be long or something
// just see what construct JPA tries to call
private int employeeCount;
public DepartmentInfo( Department d, int count ) {
department = d;
employeeCount = count;
}
// getters and setters here
}
Then your select becomes
SELECT new my.package.DepartmentInfo( D,
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID))
FROM DEPARTMENT D
With that you can use the DepartmentInfo to get the properties you are interested in.
You could create a member in your entity as an additional column, and then reference it with an alias in your query. The column name in the #Column annotation must match the alias.
Say, for your original query, you can add a countEmployees member as following. Also add insertable=false and updatable=false so the entity manager wont try to include it in insert or update statements:
public class Department {
#Column(name="DEPARTMENT_ID")
Long departmentId;
#Column(name="DEPARTMENT_NAME")
String departmentName;
#Column(name="countEmployees", insertable=false, updatable=false)
Long countEmployees;
//accessors omitted
}
And your query:
SELECT D.DEPARTMENT_NAME,
(SELECT COUNT(*) FROM EMPLOYEE E WHERE E.DEPARTMENT_ID = D.DEPARTMENT_ID) AS countEmployees
FROM DEPARTMENT D
This also applies when working with Spring Data Jpa Repositories.