Grails, левое внешнее соединение - PullRequest
2 голосов
/ 28 июня 2011

У меня есть два класса домена Users и Projects, такие как следующие

Users{
    String firstName
    String lastName
    String emailAddress
    static hasMany = [projects:Projects]
}



class Projects {
    String projectName
    String description
    Users projectLead
    Date completionDate
    static belongsTo = Users
}

Здесь completeDate == null означает, что проект еще не завершен.

Теперь я хочу отправить каждому пользователю напоминание по электронной почте о его незавершенных проектах. Как написать запрос для извлечения незавершенных проектов на пользователя?

Я думал о следующих строках, но все еще не могу идти дальше. Для того, чтобы отправить электронное письмо, мне понадобятся пользователи emailid, все незавершенные проекты и названия их

def users = Users.list()
       for(user in users){
           user.projects.find{it.completionDate==null}
       }

Можно ли использовать createCriteria в таком случае?

Ответы [ 2 ]

4 голосов
/ 28 июня 2011

Я думаю, что это должно работать:

def usersAndIncompleteProjects = Users.withCriteria {
    projects {
        isNull( completionDate )
    }
}

Это должно просто вернуть вам пользователей с незавершенными проектами, а свойство projects для каждого User будет содержать только незавершенные проекты.Если вы хотите, чтобы пользователи загружали все свои проекты, я считаю, что вам нужно использовать псевдоним


Тестирование ...

С учетом класса User:

package criteriatest

class User {
    String name

    static hasMany = [ projects: Project ]
}

и класса Project:

package criteriatest

class Project {
    String name
    Date completionDate

    static belongsTo = User

    static constraints = {
        completionDate( nullable:true )
    }
}

Этот интеграционный тест проходит (надеюсь, объяснения объяснят)

package criteriatest

import grails.test.*

class UserTests extends GroovyTestCase {
    protected void setUp() {
        super.setUp()
        User.withSession { session ->
            def tim = new User( name:'tim' )
            def dave = new User( name:'dave' )

            [ tim, dave ]*.save()

            def project1 = new Project( name:'project 1', completionDate:null )
            def project2 = new Project( name:'project 2', completionDate:new Date() )

            tim.addToProjects project1
            tim.addToProjects project2

            [ project1, project2 ]*.save()

            session.flush()
            session.clear()
        }
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testQuery() {
        def usersAndIncompleteProjects = User.withCriteria {
            projects {
                isNull 'completionDate'
            }
            order 'name', 'asc'
        }

        // We get two users back (users with no projects get returned as well)
        assert usersAndIncompleteProjects.size() == 2

        // First user (dave) has no projects
        assert usersAndIncompleteProjects[0].projects.size() == 0

        // Second user (tim) has one project (with a null completionDate)
        assert usersAndIncompleteProjects[1].projects.size() == 1

        // Check it's the right project
        assert usersAndIncompleteProjects[1].projects*.name == [ 'project 1' ]
    }
}

(это SQL-запрос, выполняемый в данном случае критерием):

select
    this_.id as id1_1_,
    this_.version as version1_1_,
    this_.name as name1_1_,
    projects3_.user_projects_id as user1_3_,
    projects_a1_.id as project2_3_,
    projects_a1_.id as id0_0_,
    projects_a1_.version as version0_0_,
    projects_a1_.completion_date as completion3_0_0_,
    projects_a1_.name as name0_0_ 
from
    user this_ 
left outer join
    user_project projects3_ 
        on this_.id=projects3_.user_projects_id 
left outer join
    project projects_a1_ 
        on projects3_.project_id=projects_a1_.id 
where
    (
        projects_a1_.completion_date is null
    ) 
order by
    this_.name asc
3 голосов
/ 28 июня 2011

Я не уверен, что эта проблема требует левого соединения, если вы не хотите включать проекты с нулевым пользователем. Почему бы просто не выбрать все проекты с нулевыми датами завершения и присоединиться к пользователю?

В HQL это будет выглядеть примерно так:

Projects.executeQuery('from Projects p join p.projectLead u where p.completionDate is null')

Вы можете сделать подобное в запросе критерия:

Projects.withCriteria {
    isNull('completionDate')
    join('projectLead')
}
...