Grails joinTable query issue - sql

I have a User domain and a Role domain and a working joinTable coded on the User side as
static hasMany = [ roles: Role ]
...
static mapping = {
table 'user_data'
id column: 'employee_number', name: 'employeeNumber', generator: 'assigned', type: 'int'
version false
sort 'lastName'
roles joinTable: [ name: 'user_role' ]
}
I am trying to query the database to pull all users with a security officer role with
def roleInstance = Role.find { name == 'security_officer' }
def secList = User.findAll("from User as u where u.roles = :roleInstance", [roleInstance:roleInstance])
But I am getting the error
Class: com.microsoft.sqlserver.jdbc.SQLServerException
Message: The value is not set for the parameter number 1.
What am I doing wrong?

I figured it out with a bunch of guess and checking.
def roleInstance = Role.findByName("security_officer")
def query = User.where {
roles {
id == roleInstance.id
}
}
def securityOfficerList = query.list()

Roles is a hasMany relationship so I think following should work.
def secList = User.findAll("from User as u where u.roles in (:roleInstance)", [roleInstance:[roleInstance]])

User has many roles, so in query you can't use u.roles = roleInstance.Try to use in [list of roles] or you can try the following query:
def secList = User.findAll("from User as u where u.roles in (from Role r where r.name=:roleInstance)", [roleInstance:roleInstance])

Related

get user role by user id in moodle

I want to get user role from user id. I am using loop in my code where i want to show all user except admin. i used below code but its not working.
$context = get_context_instance (CONTEXT_SYSTEM);
$roles = get_user_roles($context, $USER->id, false);
$role = key($roles);
$roleid = $roles[$role]->roleid;
Its provide me blank array as like screenshot. Also below my all code.
https://prnt.sc/gq8p12
$allUsers = $DB->get_records('user');
$SQL = "SELECT * FROM `".$CFG->prefix."config` WHERE `name` LIKE 'siteadmins'";
$getSiteAdmins = $DB->get_record_sql($SQL);
$explodeAdminIds = explode(',', $getSiteAdmins->value);
$context = get_context_instance (CONTEXT_SYSTEM);
if(!empty($allUsers))
{
foreach ($allUsers as $allUser)
{
if(!in_array($allUser->id, $explodeAdminIds))
{
$roles = get_user_roles($context, $allUser->id, false);
$role = key($roles);
$roleid = $roles[$role]->roleid;
echo 'USER ID -- '.$allUser->id.' >>> ';
print_r($roles); echo '<br>';
$name = ''.$allUser->id.'_'.$allUser->firstname.' '.$allUser->lastname.'';
$confirmed = ($allUser->confirmed == 1) ? 'Active' : 'In-active';
$table->data[] = array(
$i,
$name,
'Team Name',
$allUser->email,
$allUser->phone1,
'Role',
$confirmed,
//empty($coachusrarr)?'--':implode(',',$coachusrarr),
//empty($tmpleaderarr)?'--':implode(',',$tmpleaderarr),
//$coach,
);
$i++;
}
}
}
The basic problem is that get_user_roles($context, $userid) will only get you a list of roles assigned at that particular context level. Very few users have roles assigned at the system context, it is much more usual for roles to be assigned at a course level. This allows users to have different roles in different courses (a teacher on one course, might be enrolled as a student on another course).
If you want to get all the roles for a user, then you're going to need to do something like this:
$roleassignments = $DB->get_records('role_assignments', ['userid' => $user->id]);
You can then loop through all the $roleassignments and extract the 'roleid' from them (alternatively, you could use the $DB->get_fieldset command, to extract the roleids directly).
Note also that you should be using context_system::instance() instead of the old get_context_instance(CONTEXT_SYSTEM) (unless you are using a very old and insecure version of Moodle).
For getting the site admins, use get_admins() (or, if you really want to access the config value, use $CFG->siteadmins).
If you want to get a user role for a course by user id then this script will help you.
$context = context_course::instance($COURSE->id);
$roles = get_user_roles($context, $USER->id, true);
$role = key($roles);
$rolename = $roles[$role]->shortname;

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)

Grails query to filter on association and only return matching entities

I have the following 1 - M (one way) relationship:
Customer (1) -> (M) Address
I am trying to filter the addresses for a specific customer that contain certain text e.g.
def results = Customer.withCriteria {
eq "id", 995L
addresses {
ilike 'description', '%text%'
}
}
The problem is that this returns the Customer and when I in turn access the "addresses" it gives me the full list of addresses rather than the filtered list of addresses.
It's not possible for me to use Address.withCriteria as I can't access the association table from the criteria query.
I'm hoping to avoid reverting to a raw SQL query as this would mean not being able to use a lot functionality that's in place to build up criteria queries in a flexible and reusable manner.
Would love to hear any thoughts ...
I believe the reason for the different behavior in 2.1 is documented here
Specifically this point:
The previous default of LEFT JOIN for criteria queries across associations is now INNER JOIN.
IIRC, Hibernate doesn't eagerly load associations when you use an inner join.
Looks like you can use createAlias to specify an outer join example here:
My experience with this particular issue is from experience with NHibernate, so I can't really shed more light on getting it working correctly than that. I'll happily delete this answer if it turns out to be incorrect.
Try this:
def results = Customer.createCriteria().listDistinct() {
eq('id', 995L)
addresses {
ilike('description', '%Z%')
}
}
This gives you the Customer object that has the correct id and any matching addresses, and only those addresses than match.
You could also use this query (slightly modified) to get all customers that have a matching address:
def results = Customer.createCriteria().listDistinct() {
addresses {
ilike('description', '%Z%')
}
}
results.each {c->
println "Customer " + c.name
c.addresses.each {address->
println "Address " + address.description
}
}
EDIT
Here are the domain classes and the way I added the addresses:
class Customer {
String name
static hasMany = [addresses: PostalAddress]
static constraints = {
}
}
class PostalAddress {
String description
static belongsTo = [customer: Customer]
static constraints = {
}
}
//added via Bootstrap for testing
def init = { servletContext ->
def custA = new Customer(name: 'A').save(failOnError: true)
def custB = new Customer(name: 'B').save(failOnError: true)
def custC = new Customer(name: 'C').save(failOnError: true)
def add1 = new PostalAddress(description: 'Z1', customer: custA).save(failOnError: true)
def add2 = new PostalAddress(description: 'Z2', customer: custA).save(failOnError: true)
def add3 = new PostalAddress(description: 'Z3', customer: custA).save(failOnError: true)
def add4 = new PostalAddress(description: 'W4', customer: custA).save(failOnError: true)
def add5 = new PostalAddress(description: 'W5', customer: custA).save(failOnError: true)
def add6 = new PostalAddress(description: 'W6', customer: custA).save(failOnError: true)
}
When I run this I get the following output:
Customer A
Address Z3
Address Z1
Address Z2

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.

Django ORM equivalent

I have the following code in a view to get some of the information on the account to display. I tried for hours to get this to work via ORM but couldn't make it work. I ended up doing it in raw SQL but what I want isn't very complex. I'm certain it's possible to do with ORM.
In the end, I just want to populate the dictionary accountDetails from a couple of tables.
cursor.execute("SELECT a.hostname, a.distro, b.location FROM xenpanel_subscription a, xenpanel_hardwarenode b WHERE a.node_id = b.id AND customer_id = %s", [request.user.id])
accountDetails = {
'username': request.user.username,
'hostname': [],
'distro': [],
'location': [],
}
for row in cursor.fetchall():
accountDetails['hostname'].append(row[0])
accountDetails['distro'].append(row[1])
accountDetails['location'].append(row[2])
return render_to_response('account.html', accountDetails, context_instance=RequestContext(request))
It would be easier if you post models. But from SQL I'm assuming the models are like this:
class XenPanelSubscription(models.Model):
hostname = models.CharField()
distro = models.CharField()
node = models.ForeignKey(XenPanelHardwareNode)
customer_id = models.IntegerField()
class Meta:
db_table = u'xenpanel_subscription'
class XenPanelHardwareNode(models.Model):
location = models.CharField()
class Meta:
db_table = u'xenpanel_hardwarenode'
Based on these models:
accountDetails = XenPanelSubscription.objects.filter(customer_id = request.user.id)
for accountDetail in accountDetails:
print accountDetail.hostname, accountDetail.distro, accountDetail.node.location