How to query all the owned objects in one query MTM? - postgresql

I have a list of the owning side of a many-to-many relationship. How do I query all the owned objects in one query using Grails GORM? In SQL I would used the join table and the owned table and the ids for the owning table with an in clause.
Example domain classes:
class Book {
static belongsTo = Author
static hasMany = [authors:Author]
String title
}
class Author {
static hasMany = [books:Book]
String name
}
So I have a List or Set of Authors and I want to find all their Books in one query.
select b.*
from book b
join author_book ab on b.id = ab.book_id
where ab.author_id in (1, 2, 3);
In Grails I tried the following but it fails.
def books = Book.withCriteria {
inList('authors', authors)
}

You need to join the author first:
def books = Book.withCriteria {
authors {
inList('id', authors*.id)
}
}

Is this what you're looking for?
Book.findAllByAuthorInList(authors)

Related

Build up IQueryable including additional tables based on conditions

I have an issue where we create a complex IQueryable that we need to make it more efficient.
There are 2 tables that should only be included if columns from them are being filtered.
My exact situation is complex to explain so I thought I could illustrate it with an example for cars.
If I have a CarFilter class like this:
public class CarFilter
{
public string BrandName { get;set; }
public decimal SalePrice {get; set; }
}
Let's say that we have a query for car sales:
var info = from car in cars
from carSale in carSales on carSale.BrandId == car.BrandId && car.ModelId == carSale.ModelId
from brand in carBrands on car.BrandId == brand.BrandId
select car
var cars = info.ToList();
Let's say that this is a huge query that returns 100'000 rows as we are looking at cars and sales and the associated brands.
The user only wants to see the details from car, the other 2 tables are for filtering purposes.
So if the user only wants to see Ford cars, our logic above is not efficient. We are joining in the huge car sale table for no reason as well as CarBrand as the user doesn't care about anything in there.
My question is how can I only include tables in my IQueryable if they are actually needed?
So if there is a BrandName in my filter I would include CarBrand table, if not, it's not included.
Using this example, the only time I would ever want both tables is if the user specified both a BrandName and SalePrice.
The semantics are not important here, i.e the number of records returned being impacted by the joins etc, I am looking for help on the approach
I am using EF Core
Paul
It is common for complex filtering. Just join when it is needed.
var query = cars;
if (filter.SalePrice > 0)
{
query =
from car in query
join carSale in carSales on new { car.BrandId, car.ModelId } equals new { carSale.BrandId, carSale.ModelId }
where carSale.Price >= filter.SalePrice
select car;
}
if (!filter.BrandName.IsNullOrEempty())
{
query =
from car in query
join brand in carBrands on car.BrandId equals brand.BrandId
where brand.Name == filter.BrandName
select car;
}
var result = query.ToList();

How to update a ManyToMany relationship in Objection JS?

I am learning Objection JS. I have a manyToMany relationship on an accounts and roles table that are related through an accounts_roles table. I was wondering if there was a way to update account roles on the account model by doing something like:
AccountOne.addRoles([roleId])
AccountOne.removeRoles([roleId])
AccountOne.updateRoles([roleId])
AccountOne.deleteRoles([roleId])
I searched online and went through the official objection documentation. So far I can do a GraphInsert, on my account model with a role object "x", and that creates a new role "x" with a relationship correctly defined in accounts_roles. But that always creates a new role. I would like to add and remove relationships between existing accounts and roles. Any help would be much appreciated.
You can use relate and unrelate to connect two rows together in a many-to-many relationship. Obviously, for this to work, you have to have your Models' relationMappings set up correctly. I have put a pair of example models too. It's critical that you match your key of your relationMappings to what you put in your $relatedQuery method to call relate/unrelate on.
Example Models
//Person and Movie Models
const { Model } = require('objection');
class Person extends Model {
static tableName = 'persons';
static get relationMappings() {
return {
movies: {
relation: Model.ManyToManyRelation,
modelClass: Movie,
join: {
from: 'persons.id',
through: {
from: 'persons_movies.person_id',
to: 'persons_movies.movie_id'
},
to: 'movies.id'
}
}
};
}
}
class Movie extends Model {
static tableName = 'movies';
static get relationMappings() {
return {
persons: {
relation: Model.ManyToManyRelation,
modelClass: Person,
join: {
from: 'movies.id',
through: {
from: 'persons_movies.movie_id',
to: 'persons_movies.person_id'
},
to: 'persons.id'
}
}
};
}
}
Relate Example
In the case of a many-to-many relation, creates a join row to the join table.
const person = await Person
.query()
.findById(123);
const numRelatedRows = await person
.$relatedQuery('movies')
.relate(50);
// movie with ID 50 is now related to person with ID 123
// this happened by creating a new row in the linking table for Movies <--> Person
Unrelate Example
For ManyToMany relations this deletes the join row from the join table.
const person = await Person
.query()
.findById(123)
const numUnrelatedRows = await person
.$relatedQuery('movies')
.unrelate()
.where('id', 50);
// movie with ID 50 is now unrelated to person with ID 123
// this happened by delete an existing row in the linking table for Movies <--> Person

How to create association one to many and many to one between two entities in gorm?

I'm new in Grails. I have a problem with generation association many to one and one to many between two tables. I'm using postgresql database.
Employee.groovy
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
EmployeePlan.groovy
class EmployeePlan {
AcademicYear academicYear
HourType hourType
int hours
float weightOfSubject
Employee employee
static belongsTo = [SubjectPlan]
}
I'd like to have access from employee to list of employeePlans and access from EmployeePlan to Employee instance. Unfortunately GORM generates only two tables Employee and EmployeePlan with employee_id. I don't have third table which should have two columns employee_id and employee_plan_id. Could you help me ?
I think your setup is correct, as you write from Employee class you can access to a collection of EmployeePlan (take care, that if you don't explicitly define EmployeePlan like a List, it will be a Set by default) and from EmployeePlan you can access Employee.
If you need List, you can define it like that:
class Employee {
String firstName
String lastName
int hoursLimit
Contact contact
Account account
Unit unit
char isBoss
//explicitly define List
List<EmployeePlan> employeePlans
static hasMany = [positionTypes:PositionType, employeePlans: EmployeePlan]
}
But back to your question. You'd like to have join table between Employee and employeePlan, but why? Its not necessary, since you have bidirectional mapping with sets (unordered), grails will not create a join table. Can you explain why do you need it? In grails the references will be auto-populated, so I don't see any issue here.
If need to preserve order of employeePlans, then define it as List, shown above, and grails will create a join table with corresponding indexes.
have you read the ref-doc? it gives you the answer immediately:
class Person {
String firstName
static hasMany = [addresses: Address]
static mapping = {
table 'people'
firstName column: 'First_Name'
addresses joinTable: [name: 'Person_Addresses',
key: 'Person_Id',
column: 'Address_Id']
}
}

Using Inner joins in Entity Framework on multiple tables?

I have a student table in my database with columns Id, Name, DepartmentId, CollegeId, CityId etc and a Department table, College table to map to the DepartmentId, CollegeId in the Student table.
Now I want to pass CityId and retrieve Id, Name, DepartmentName, CollegeName with help of the corresponding tables using inner join based on the CityId.
I'm implementing a method FindAll() which takes in CityId as the input parameter and retrieves data based on CityId
public IEnumerable<StudentRegionEntity> FindAll(int CityId)
{
var totalStudents = new List<StudentRegionEntity>();
foreach(var entity in this.Dbcontext.Students)
{
}
}
In the foreach loop I want to bind the list of students with Id, Name, Department, College fields, how can I use joins and implement the functionality for FindAll()?
var studentEntities = this.Dbcontext.Students
.Include("StudentList").Where(s => s.cityId == CityId).ToList()
this will give the list of all the StudentEntity entities with StudentRegionEntity attached, using one join query to the database.

JPA OneToMany relations and performace

I have two entities: parent Customer and child Order.
Each Customer has 1,000,000 Orders for example, so it is not needed in any given time to load a Customer with all Orders but I want to have this ability to make join query on these two entities in JPA.
So because of this, I must create #OneToMany relationship for making join queries.
My question is: how to get query without making joinColumn because even in Lazy mode it is possible to load 1,000,000 objects!
I just want to get query on these object with where restrictions like native join.
If you don't want the #OneToMany relationship implicitly set in your Customer class than you don't have to. You can execute JPQL queries (in very precise manner) without the marked relationship.
Assume you have:
#Entity
public class Customer {
// all Customer-related fields WITHOUT #OneToMany relationship with Order
}
#Entity
public class Order {
#ManyToOne
private Customer owner;
}
Then if you want to get all Orders for particular Customer you can execute a simple JPQL query like that:
// Customer customer = ...
// EntityManager em = ...
String jpql = "SELECT o FROM Order o WHERE o.owner = :customer";
TypedQuery<Order> query = em.createQuery(jpql, Order.class);
query.setParameter("customer", customer);
List<Order> orders = query.getResultList();
In this way you can execute the code only when you're really sure you want to fetch Customer's orders.
I hope I've understood your problem correctly.
EclipseLink has support for QueryKeys, that allow you to define fields or relationships for querying that are not mapped. Currently there in no annotation support for query keys, but you can define them using the API and a DescriptorCustomizer.
Also you do not need the OneToMany to query on it, just use the inverse ManyToOne to query,
i.e.
Select distinct c from Customer c, Order o where o.customer = c and o.item = :item
Or,
Select distinct o.customer from Order o join o.customer c where o.customer = c and o.item = :item