【问题标题】:Dynamically creating a query based on params being passed to a controller根据传递给控制器​​的参数动态创建查询
【发布时间】:2013-04-11 11:23:02
【问题描述】:

在我的任务管理应用程序中,用户应该能够根据:assignedToprioritystatus 和/或dueDate 过滤任务

我不确定如何创建动态查询,因为它将根据可用参数构建查询。

例如:

如果我有一个 URL,例如:task/index?assignedTo=1&status=2

我可以仅基于这两个参数构建查询。我习惯的方法是

Task.findAllByAssignedToAndStatus(
   User.get(params.assignedTo),
   TaskStatus.get(params.status)
)

我显然不想通过为每个可能的 URL 参数组合写出每个 findAllBy 查询来实现 DRY 方法。

在 grails 中有没有好的方法来做到这一点?

【问题讨论】:

  • 通过"findAllBy${params.collect { k, v -> k.capitalize() }.join( 'And' )}" 之类的操作来生成查找器名称很简单,但它怎么知道assignedTo 应该加载User 实例而status 应该引用TaskStatus ?
  • 同意,我不想这样做。这是一篇论文,所以我希望代码尽可能干净。
  • 我可以建议一个命名查询 - grails.org/doc/2.2.1/ref/Domain%20Classes/namedQueries.html - 然后您可以按用户和状态过滤掉。我认为他们摇滚!

标签: grails groovy grails-orm


【解决方案1】:

我们已经在域类上实现了过滤器功能来做到这一点。简而言之,您将命名查询的小型 sn-ps 添加到您的域类中。

例子:

class Employee {

    String firstname
    String lastname
    Integer age

    static constraints = {
    }

    static namedQueries = {
        filteronFirstname { String inFirstname ->
            if (inFirstname&& inFirstname?.size() > 0) {
                ilike 'firstname', "%${inFirstname}%"
            }
        }

        filteronLastname { String inLastname ->
            if (inLastname && inLastname?.size() > 0) {
                ilike 'lastname', "%${inLastname}%"
            }
        }

        filteronAgeOlderThen { String ageOlderThen ->
            if (age && age ?.size() > 0) {
                gt 'age', ageOlderThen as Integer
            }
        }

    }
}

这启用了细粒度过滤器功能,因此您可以构建 1 个使用所有过滤器方法的列表方法,并根据用户提供的输入将命名查询连接在一起。

Employee.filteronFirstname("John").
filterOnLastname("Doe").
filteronAgeOlderThen("10").
list(params)

【讨论】:

    【解决方案2】:

    我设法使用createCriteria 来完成这项工作,如下所示:

    如果用户为该特定过滤器选择“全部”,我将值 0 用于任何参数,因此它将从 where 子句中省略,即该参数没有 eq() 语句。

    一个sn-p的代码:

    else
        {       
            def assignedTo = Integer.parseInt(taskParams.assignedTo)
            def priority = Integer.parseInt(taskParams.priority)
            def status = Integer.parseInt(taskParams.status)
    
            tasks = Task.createCriteria().list {            
    
                eq("project", Project.get(taskParams.PId))
    
                if(assignedTo > 0)
                    eq("assignedTo", User.get(assignedTo))
    
                if(priority > 0)
                    eq("priority", TaskPriority.get(priority))
    
                if(status > 0)
                    eq("status", TaskStatus.get(status))                
            }           
        }
        return tasks
    }
    

    【讨论】:

      【解决方案3】:

      我会为此考虑使用可搜索插件 (http://grails.org/plugin/searchable)。指定Task 的哪些属性应该是可搜索的很容易。

      【讨论】:

        【解决方案4】:

        看看fluent接口,你可以使用它们来添加或删除(过滤)每个参数。

        http://en.wikipedia.org/wiki/Fluent_interface

        【讨论】:

          【解决方案5】:

          我对来自 URL 的动态 Where 查询的解决方案:

          if (params.query) {
              def classLoader = getClass().getClassLoader();
              def query = new GroovyShell(classLoader).evaluate(
                      "import myapp.Visit; Visit.where {$params.query}")
              visits = query.list(params)
          } 
          

          这会从这样的 URL 中获取约束:

          visit/index?query=client.status=='suspect';atHome==false
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-05-14
            • 2018-08-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-22
            相关资源
            最近更新 更多