grails:将SQL转换为域类

时间:2012-09-28 20:26:43

标签: grails groovy

我正在开发一个GRAILS应用程序(我是GRAILS的新手并继承了之前开发人员的项目)。我正在慢慢了解GRAILS如何运作以及DOMAIN类,hibernate等的使用.MySQL数据库托管在亚马逊上,我们正在使用ElasticCache。

您是否有更多知识渊博的人知道如何将以下SQL语句转换为域类和查询条件。

if(params?.searchterm) {

    def searchTerms = params.searchterm.trim().split( ',' )
    def resultLimit = params.resultlimit?: 1000
    def addDomain = ''

    if (params?.domainname){
        addDomain = " and url like '%${params.domainname}%' "
    }

    def theSearchTermsSQL = ""

    /*
     *  create c.name rlike condition for each search term
     *
     */
    searchTerms.each{
        aSearchTerm -> 
            if( theSearchTermsSQL != '' ){
                theSearchTermsSQL += ' or '
            }
            theSearchTermsSQL += "cname rlike '[[:<:]]" + aSearchTerm.trim() +  "[[:>:]]'"
    }

    /*
     *  build query
     *
     */
    def getUrlsQuery = "select
        u.url as url,
        c.name as cname,
        t.weight as tweight
    from
       (category c, target t, url_meta_data u )
    where
       (" + theSearchTermsSQL + ")
    and 
        t.category_id = c.id
        and t.url_meta_data_id = u.id
        and u.ugc_flag != 1 " + addDomain + "
    order by tweight desc
    limit " + resultLimit.toLong()


    /* 
     *  run query
     *
     */
    Sql sqlInstance = new Sql( dataSource )

    def resultsList = sqlInstance.rows( getUrlsQuery )

}

表格如下(虚拟数据):

[Category]
id | name
-----------
 1 | small car
 2 | bike
 3 | truck
 4 | train
 5 | plane
 6 | large car
 7 | caravan

[Target]
id | cid | weight | url_meta_data_id
----------------------------------------
 1 |  1  |  56    |        1
 2 |  1  |  76    |        2
 3 |  3  |  34    |        3
 4 |  2  |  98    |        4
 5 |  1  |  11    |        5
 6 |  3  |  31    |        7
 7 |  5  |  12    |        8
 8 |  4  |  82    |        6

[url_meta_data]
id | url                          | ugc_flag
---------------------------------------------
 1 | http://www.example.com/foo/1 |    0
 2 | http://www.example.com/foo/2 |    0
 3 | http://www.example.com/foo/3 |    1
 4 | http://www.example.com/foo/4 |    0
 5 | http://www.example.com/foo/5 |    1
 6 | http://www.example.com/foo/6 |    1
 7 | http://www.example.com/foo/7 |    1
 8 | http://www.example.com/foo/8 |    0

域类

class Category {

    static hasMany = [targets: Target]

    static mapping = {
        cache  true
        cache usage: 'read-only'
        targetConditions cache : true
    }

    String name

    String source
}

class Target {

    static belongsTo = [urlMetaData: UrlMetaData, category: Category]
    static mapping = {
        cache true
        cache usage: 'read-only'
    }

    int weight

}

class UrlMetaData {

    String url

    String ugcFlag

    static hasMany = [targets: Target ]

    static mapping = { 
        cache true
        cache usage: 'read-only'
    }

    static transients = ['domainName']

    String getDomainName() {

        return HostnameHelper.getBaseDomain(url)
    }
}

基本上,来自url_meta_data的网址可以与许多类别相关联。所以本质上我想要实现的应该是一个相对基本的操作...返回搜索词'car'的所有url,它们的权重(即重要性)以及ugc_flag的位置不是1(即url不是用户生成的内容)。数据库中有100K以上的记录,这些记录是从第三方提供程序导入的。请注意,所有URL都属于我的客户端 - 这里没有做任何狡猾的事情。

请注意我在查询中使用的rlike - 我最初使用的是ilike%searchterm%,但是会找到类别,其中searchterm是更大词的一部分,例如'caravan') - 不幸的是,虽然rlike不会如果用户请求“汽车”,则返回任何内容。

我编辑了代码 - 因为Igor指出了'domainName'最初的奇怪包含。这是一个传递的可选参数,允许用户过滤仅某个域的网址(例如'example.com')

2 个答案:

答案 0 :(得分:0)

我创建了一个给定域对象的空列表, 循环遍历resultsList,从每一行构造一个域对象,并将其添加到这些对象的列表中。然后从控制器返回该列表以查看。这就是你要找的东西吗?

答案 1 :(得分:0)

1)如果它是从头开发的Grails应用程序(而不是基于遗留数据库结构),那么您可能应该已经拥有域类CategoryTargetUrlMetaData(否则你必须手动或使用db-reverse-engineer插件创建它们

2)我认为Target有一个字段Category categoryCategory有一个字段UrlMetaData urlMetaData

3)可行的方法可能是http://grails.org/doc/2.1.0/ref/Domain%20Classes/createCriteria.html,我将尝试概述您特定案例的基础知识

4)不确定theDomain意味着什么 - 可能是代码气味,以及从客户端接受rlike个参数

5)以下代码根本没有经过测试 - 特别是我不确定嵌套标准内部的分离是否有效。但这可能是一个合适的起点; logging sql查询应该有助于使其工作(How to log SQL statements in Grails

def c = Target.createCriteria() //create criteria on Target
def resultsList = c.list(max: resultLimit.toLong()) { //list all matched entities up to resultLimit results
    category { //nested criteria for category
        //the following 'if' statement and its body is plain Groovy code rather than part of DSL that translates to Hibernate Criteria
        if (searchTerms) { //do the following only if searchTerms list is not empty
            or { // one of several conditions
                for (st in searchTerms) { // not a part of DSL - plain Groovy loop
                    rlike('name', st.trim())) //add a disjunction element
                }
            }
        }
        urlMetaData { //nested criteria for metadata
            ne('ugcFlag', 1) //ugcFlag not equal 1
        }
    }    
    order('weight', 'desc') //order by weight
}

明确写明

时,or限制可能效果更好
if (searchTerms) { 
    def r = Restrictions.disjunction() 
    for (st in searchTerms) {
        r.add(new LikeExpression('name', st.trim()))
    }
    instance.add(r) //'instance' is an injected property
}

干杯,
伊戈尔西内夫