I have a Spring Data JPA Entity
#Entity
public class User {
private static final long serialVersionUID = 1L;
#Id
private Long id;
Which I want to include a property mutualFriends which is the result of a query against the querying user principle (in Spring Security), using SpEL and the EvaluationContext extension model?:
Following the SpEL examples I came up with something like this:
#Formula("select count(friendship) from Friendship friendship where " +
"friendship.owner.id = id " +
"and friendship.friend in " +
"(SELECT f.friend FROM Friendship f where f.owner.id = " +
"?#{principle != null ? principal.id : id}) ")
private Integer mutualFriends;
The same entity (User) is used when authentication user's so I need to have some logic to determine if the principle is available yet or I get an error:
Caused by: org.postgresql.util.PSQLException: No value specified for
parameter 2.
?#{principle != null ? principal.id : id}
Is this formatted correctly?
Here is the relevant part of the hibernate query that is executed when I get the exception:
select user0_.id as id1_19_, user0_.created_by as created_2_19_, user0_.created_date as created_3_19_, user0_.last_modified_by as last_mod4_19_, user0_.last_modified_date as last_mod5_19_, user0_.activated as activate6_19_, user0_.activation_key as activati7_19_, user0_.avatar_url as avatar_u8_19_, user0_.banner_url as banner_u9_19_, user0_.description as descrip10_19_, user0_.email as email11_19_, user0_.first_name as first_n12_19_, user0_.lang_key as lang_ke13_19_, user0_.last_name as last_na14_19_, user0_.login as login15_19_, user0_.online as online16_19_, user0_.password_hash as passwor17_19_, user0_.reset_date as reset_d18_19_, user0_.reset_key as reset_k19_19_, user0_.test_data as test_da20_19_,
select count(user0_.friendship)
from Friendship friendship
where friendship.friend in (
SELECT f.friend
FROM Friendship f
where f.owner.id = COALESCE(?#{principle != null ? principal.id : user0_.null},user0_.id))
and friendship.owner.id = user0_.id as formula2_
from user user0_ where user0_.login=?
SpEL/JPA correctly implements replaces id with user0_.id, but something is still missing? Also, it does not appear that select count(user0_.friendship) from Friendship friendship where friendship.friend in (SELECT f.friend FROM Friendship f where f.owner.id = COALESCE(?#{principle != null ? principal.id : user0_.null},user0_.id)) and friendship.owner.id = user0_.id as formula2_ portion of the query has been correctly parsed?
Sorry, completely missed the obvious:
#Formula is a Hibernate thing. It knows nothing about SpEL and wound evaluate such expressions.
What you can do, and what the example you linked to does is: create a method in your repository, add a #Query annotation and use SpEL in there.
I think the problem might be that id is not known in the SpEL context. Replacing the SpEL expression with
COALESCE(?#{principle != null ? principal.id : null},id)
should do the trick.
Related
I have an array of Persons (class contain name and lastname and id )
what I have to do is to return a string form this array but in a specific format an example will be more explicative
array=[PERS1,PERS2]
I need this as a return value : "The name of all persons : "+ PERS1.name + PERS1.LASTN + " , " + PERS2.name +PERS2.LASTN +","
I know this method
array.each{ |per|
#but this will not return the format ,and with each I think I can only print (I'm new in the ruby field
}
all of this because I need it when overriding to_s , because I need to provide a string -> to_s
def to_s
"THE name of all preson"+#array.each #will not work as I want
end
Thank you for ur time and effort and if you need any clarification please let me know
each just iterates over a collection and returns the collection itself. You may want to use map and join the result.
array.map { |person| "#{person.name} #{person.lastn}" }.join(',')
Or if you modify your Person class it can be even simpler.
# I assume that the name of the class is Person and name and lastn are always present
class Person
def full_name
"#{person.name} #{person.lastname}"
end
end
# Then you can call this method on `map`.
array.map(&:full_name).join(',')
Try this,
array.each do |per|
"#{per.name} #{per.LASTN}"
end
For more info check Interpolation
I have two domains that are connected with one-to-many relation - One User may have many Associations. I want to view all associations that belong to this user. I'm using scaffolding plugin. So code that should return list of Associations in AssociationController looks lile this:
def index(Integer max) {
respond Association.list(params), model:[associationInstanceCount: Association.count()]
}
And on the User view page I have the following code:
<g:form controller="Association" >
<fieldset class="buttons">
<g:hiddenField name="user.id" id="user.id" value="${userInstance.id}"/>
<g:actionSubmit class="list" action="index" value="${message(code: 'default.list.label', default: 'Show Associations')}"/>
</fieldset>
</g:form>
When I press this actionSubmit user.id is sent with the request and it is within params map (I checked it with debug) but for some reason Association.list(params) returns all Associations (for all users) despite the fact that I'm using this user.id within params. A also tried rename user.id to just user and it didn't work either. Seems like this .list() should be used only for sorting or I'm doing something wrong. Can you help me with this please? Thank you!
To clarify the given answer: list( params ) returns ALL results for the domain object, and accepts only sorting (order by) and view-port (limit/offset) parameters. It does not provide any where clause (well, apart from discriminator-column)
UPDATE:
you can use findAllBy*:
Association.findAllByUserId( params.long( 'user.id' ), params )
or criteria if you need to make your query more complex:
Association.withCriteria{
eq 'id', params.long( 'user.id' )
maxResults params.int( 'max' ) ?: 10
firstResult params.int( 'offset' ) ?: 0
if( params.sort && params.order ) order params.sort, params.order
}
According to Grails documentation, list does not take an id as parameter.
Seeing your max, it would be Association.list(max: max) and for what you want, it is something like:
Association.findAllByUserId(params.id, [max: max])
Where params.id contains the id of the wanted user (or params['user.id']).
More on findAllBy...
Not sure about the previous response but :
Association.where {
user {
eq 'id', params['user.id']
}
} .list()
You can add params to list call if you use pagination.
Another solution :
def index(User user) {
respond user.associations, , model:[associationInstanceCount: user.associations.size()]
}
But you'll have to name your param 'id'
It mostly depends on how you have designed your domain objects and what's your goal here.
I'm doing integration tests for controllers in grails.I need to pass query string in test case and I'm passing it as controller.request.queryString for the same.
My tests is getting failed. It's giving me null value for the query String parameter.
Controller - UserExController
Foll is the action on which i'm doing integration testing.In this I'm reading query string parameter 'uid' and getting the userInstance using GORM method
def getUser() {
//reading the query string parameter 'uid'
def userId = request.getParameter("uid")
User user = User.findByUsername(userId)
render view:'edit', model:[userInstance:user]
}
This is the test for the above written action .In this I'm passing the query string parameter and calling the action
class UserInstanceTests extends GroovyTestCase {
#Test
void testPerfSummaryApi() {
def userExController=new UserExController()
userExController.request.queryString='uid=rp123'
userExController.getUser()
def model = userExController.modelAndView.model.userInstance
assertNotNull model
}
}
I'm getting groovy.lang.MissingMethod.Exception in the foll call:
User.findByUsername(userId) //userId is comming null
Change in Controller:
def userId = request.getParameter("uid")
to
def userId = params.uid
Change in int test:
userExController.request.queryString='uid=rp123'
to
userExController.params.uid='rp123'
Grails' dynamic binding helps in binding the query parameters to params and request to request in the controller.
This should make things work for you (tested on Grails 2.0.4):
userExController.request.addParameter('uid', 'rp123')
However, I would recommend to turn to dmahapatro's suggestion and refactor your controller to use params.uid instead of request.getParameter("uid"). Or even introduce a command object. The way you are doing it now just does not seem to be the standard Grails way.
I have a domain class called Application as follows:
class Application {
static hasOne = [resumption:Resumption, employee:Employee]
//Employee employee
Date startDate
Date endDate
Integer amountOfDays
String leaveRecommended
String leaveNotRecommended
Date supervisorDate
String toString(){
return "Application for ${employee.lastName}, ${employee.firstName}"
}
}
In the ApplicationController I'm trying to write a query that is going to find all applications that match a particular employee id. I do so as follows:
def applicationlist(){
if(!params.max){
params.max = 10
}
def query
def criteria = Application.createCriteria()
def results
query = { eq("employee_id", Long.parseLong("1")) }
results = criteria.list(params, query)
render(view:"employeeapplicationlist", model:[applicationlist:results])
}
Now I keep getting the error: "could not resolve property: employee_id"
I've checked the generated Application table in MySql, there is a column called employee_id with a value. The weird thing is I can access any other property (like amountOfDays), so what's the deal with employee_id? Why is it complaining that it cannot resolve the property? What am I missing? Thanks in advance.
Associations in the criteria DSL are of the form
Application.withCriteria{
employee{
eq 'id', 1
}
}
http://grails.org/doc/latest/guide/GORM.html#criteria
But you could probably just do:
def employee = Employee.proxy(1)
Application.findAllByEmployee( employee )
This appears a few times in the Grails User Guide as 'querying associations'
Oh well it looks like I'm still not fully adjusted to interfacing with the database on an Object level. For anyone else with this or a similar problem, here's the fix:
query = { eq("employee.id", Long.parseLong("1")) }
Sine the Application Domain class has one Employee, then we just need to access the id field of that employee. Remember we're in the ApplicationController.
I have 3 entities:
Goods [GID(PK), GoodName]
Persons [PID(PK), PersonName]
Roles [RID(PK), RoleName]
But now I need to associate these object with each other.
In other words, each Good can have MANY Persons in MANY Roles.
I have a table in DB with 3 fields (GID, PID, RID)
For example:
Book (GID#1), can have 3 associated persons:
1. Jack (PID#1) in role Author (RID#1)
2. Jack (PID#1) in role Editor (RID#2)
3. Bill (PID#2) in role Painter (RID#3)
How can I map this in POCO format in Entity Framework 4?
I believe you have to create another PersonRoles header where you store the Person-Role relation, then you access the person+role via this one:
PersonRoles [PRID(PK), PersonName, RoleName] (note: you could also do this withnow entitykey, just relationships, EF will eliminate this entity and give a direct Person.Roles entity, which you can do access it via Book.Persons.Select((p) p.Roles)).
PersonRole#1: Jack#1/Author#1
PersonRole#2: Jack#1/Editor#2
PersonRole#3: Bill#2/Painter#3
Book.PersonRole = context.PersonRoles.
SingleOrDefault((pr) => pr.Person.PersonId == 1 && pr.RoleId == 1);
Note: my main lang is VB.NET so I apologize for the pseudu code above, but I hope you get the idea.
Update
It should be like:
<DataContract(IsReference:=True)>
<KnownType(GetType(Good))>
<KnownType(GetType(Person))>
<KnownType(GetType(Role))>
Partial Public Class GoodPersonRole
Implements IObjectWithChangeTracker
Implements INotifyPropertyChanged
<DataMember()>
Public Property GoodId() As Integer
Get
Return _goodId
End Get
Set(ByVal value As Integer)
If Not Equals(_goodId, value) Then
If ChangeTracker.ChangeTrackingEnabled AndAlso ChangeTracker.State <> ObjectState.Added Then
Throw New InvalidOperationException("The property 'GoodId' is part of the object's key and cannot be changed. Changes to key properties can only be made when the object is not being tracked or is in the Added state.")
End If
If Not IsDeserializing Then
If Good IsNot Nothing AndAlso Not Equals(Good.GoodId, value) Then
Good = Nothing
End If
End If
_goodId = value
OnPropertyChanged("GoodId")
End If
End Set
End Property
Private _goodId As Integer
<DataMember()>
Public Property Good() As Good
Get
Return _good
End Get
Set(ByVal value As Good)
If _good IsNot value Then
If ChangeTracker.ChangeTrackingEnabled AndAlso ChangeTracker.State <> ObjectState.Added AndAlso value IsNot Nothing Then
' This the dependent end of an identifying relationship, so the principal end cannot be changed if it is already set,
' otherwise it can only be set to an entity with a primary key that is the same value as the dependent's foreign key.
If Not Equals(GoodId, value.GoodId) Then
Throw New InvalidOperationException("The principal end of an identifying relationship can only be changed when the dependent end is in the Added state.")
End If
End If
Dim previousValue As Good = _good
_good = value
FixupGood(previousValue)
OnNavigationPropertyChanged("Good")
End If
End Set
End Property
Private _good As Good
End Class
(part from the generated entity by ADO.NET VB POCO Entity Generator)
I just copied the 'Good' Id and nav. property but it should be the three of them.