Say we have three Grails domain classes as follows:
class Person {
String name
static searchable = true
}
class Boss extends Person { }
class Employee extends Person { }
We then create/persist one Boss and one Employee instance:
def myBoss = new Boss(name:"Boss")
myBoss.save()
def myEmployee = new Employee(name:"Employee")
myEmployee.save()
By default, it seems the ElasticSearch plugin will index these instances as type Boss and Employee, not as type Person.
Given that only one inherited field will be searchable, is there any way to change the ElasticSearch mapping to Person rather than Boss and Employee (without using the low level API)?
This would allow us to use one query to search for all Persons by name, rather than two separate queries on Boss and Employee.
Related
I'm a Grails newbie and I found the following obstacle:
I have 2 domains: Course and Student, they have a many-to-many relationship (a Course can have several students, a student can enroll in several courses) and the student belongs to the course.
So, when I add a student to a course, I want to be able to find what Courses have added a specific student.
I tried to use:
def s = Student.get(id)
def c = Course.findAllByStudents(s)
But grails keeps telling me "No value specified for parameter 1".
Can you guys throw some light into this?
Course.findAllByStudents expects as parameter Set of Students but you are supplying it with single instance of Student, that's why you are getting "No value specified for parameter 1".
To find in what Courses is Student. If you created domain classes like this:
class Course {
//some Course attributes
static hasMany = [students: Student]
}
class Student {
//some Student attributes
static hasMany = [courses: Course]
static belongsTo = Course
}
then you can simply use s.courses.
If you are not two-way mapping that relationship. You can create criteria like this:
Course.withCriteria {
createAlias 'students', 's'
eq 's.elements', s
}
So far all the examples of queries I am coming across are geared towards a domain class such as:
Account.where, Account.withCriteria, Account.findxxxx but what if I want to query an instance's properties' properties? For example what if I have c a company instance that has a department d and I want to get a list of all the departments of this company instance that have 12 employees (a property of department) or less? What would be the code for such a query?
Something like:
c.findAllD's(such that d.numberOfEmployees <= 12)
Also, can anyone point me to literature on such instance based queries? I haven't been able to come across it.
The easiest approach would be to make the association bidirectional, i.e.
class Company {
static hasMany = [departments:Department]
}
class Department {
Company company
int numberOfEmployees
static belongsTo = [company:Company]
}
Then you can simply start your queries from the Department end, such as
def c = Company.get(...) // or however you obtain your Company instance
def departments = Department.findAllByCompanyAndNumberOfEmployeesLessThanEquals(c, 12)
looks like you want to use the Named Queries
I'm facing a issue regarding inheritance in Grails.
I have a domain class Person.grooy:
class Person{
String name
String contactNumber
Address address
}
Now I'm extending Person.groovy for Employee and Customer like:
class Employee extends Person{
String designation
}
class Customer extends Person{
String interest
}
Now I want separate table in my database for Employee and Customer having columns of Person i.e name,contactNumber and associate address key.
How could I achieve this. I searched every where but there is nothing for this aspect.
Is this one approach is not possible in GORM.
Please answer.
Thanks Guys
Finally I managed to get what I want just by placing a grails.persistence.Entity annotation to my child domain classes. I also make my parent i.e. Person.groovy abstract and place in src/groovy.
Now I have database hierarchy as I expected but some scaffold issues in controller still persist that will also sorted out with your help.
You need to disable table-per-hierarchy, which is by default enabled in Grails
class Employee extends Person{
String designation
static mapping = {
tablePerHierarchy false
}
}
table-per-hierarchy Ref
If you put your Person class in src/java or src/groovy it won't be mapped to the db.
Remember to import it into your Employee and Customer classes
import com.yourPackage.Person
class Employee extends Person{
}
It looks like inheritance is not the approach we need to follow here. You should create composition with Person class and it will store the properties of Person class in Employee.
class Employee {
Person person
String designation
static embedded = ['person']
}
Gorm Composition
you can put it inside src/java, but that solution will not be standard, as it really will not be treated as a grails domain example once you get deeper into the application.
For example, if you want to create a controller or a test script on the extended domain as per the previous answer, it will be complicated.
As of grails 2.2.x I believe, grails provides you with mapWith. You can use that for a more maintainable solution
class Employee{
static mapWith = "none"
}
We use dynamic scaffolding in our project and hence place maximum coding in Domain itself.
I have a requirement where I want to retrieve a collection for a Domain class property from the same domain class.
Example :
class Person{
String name
String school
}
school property should be a dropdown containing list of all schools so far available in the Person table. If no value available, it can be empty dropdown.
Any suggestions to achieve this in domain class itself?
That is what
static hasMany is for: http://grails.org/doc/latest/ref/Domain%20Classes/hasMany.html
in your case, something like below will work , once you create a School Domain object:
class Person{
...
static hasMany = [schools: School]
...
I'm using Grails and I want to have a unidirectional many-to-many relationship.
In my application, an Employee can "bookmark" another Employee in order to quickly access them to leave notes. Employees need not know who has bookmarked them.
In other words, I essentially want to have an employee.bookmarks property that I can use for this.
Thus far, I've found the documentation on many-to-many relationships for Grails ORM, but this seems to be exclusively across two different tables.
Sounds like you just need a regular unidirectional 1-many:
class Employee {
...
static hasMany = [bookmarks: Employee]
}
You can use transient properties and an additional table "Bookmark" to do this task:
class Employee {
String name
static transients = ["bookmarks"]
def getBookmarks() {
Bookmark.findAllByBookmarker(this, [sort: "id", order: "asc"])
}
...
}
class Bookmark implements Serializable {
Employee bookmarker // the employee who bookmark someone
Employee bookmarkee // the employee who is bookmarked
static mapping = {
table "Bookmark"
id composite: ['bookmarker', 'bookmarkee']
bookmarker(column: "BOOKMARKER_ID")
bookmarkee(column: "BOOKMARKEE_ID")
version false
}
static Bookmarker get(long bookmarkerId, long bookmarkeeId) {
find 'from Bookmark where bookmarker.id=:bookmarkerId and bookmarkee.id=:bookmarkeeId',
[bookmarkerId: bookmarkerId, bookmarkeeId: bookmarkeeId]
}
...
}
This method uses table "Bookmark" to store the relations between employees, so it is possible to have 2 people bookmark the same employee. Note that class Bookmark must implements Serializable.