grails:将 SQL 转换为域类
Posted
技术标签:
【中文标题】grails:将 SQL 转换为域类【英文标题】:grails: converting SQL into domain classes 【发布时间】:2012-09-20 17:57:38 【问题描述】:我正在开发一个 GRAILS 应用程序(我是 GRAILS 的新手,并从以前的开发人员那里继承了该项目)。我正在慢慢了解 GRAILS 的运行方式以及 DOMAIN 类、休眠等的使用。mysql db 托管在 Amazon 上,我们正在使用 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 的 url 可以关联到许多类别。所以本质上我想要实现的应该是一个相对基本的操作......返回搜索词“汽车”的所有网址、它们的权重(即重要性)以及 ugc_flag 的位置不是 1(即 url 不是用户生成的内容)。数据库中有 100K + 记录,这些记录是从第三方提供商导入的。请注意,所有 URL 都属于我的客户 - 这里没有做任何狡猾的事情。
请注意我在查询中使用的 rlike - 我最初使用的是 ilike %searchterm% 但它会找到 searchterm 是较大单词一部分的类别,例如“caravan”) - 不幸的是,尽管 rlike 不会如果用户请求“汽车”,则返回任何内容。
我编辑了代码 - 正如 Igor 指出最初包含“域名”的奇怪内容。这是传递的可选参数,允许用户仅过滤特定域的 url(例如 'example.com')
【问题讨论】:
【参考方案1】:我会创建一个给定域对象的空列表, 遍历 resultsList,从每一行构造一个域对象并将其添加到这些对象的列表中。然后将该列表从控制器返回以查看。这就是你要找的吗?
【讨论】:
感谢矢量。正如您所提到的,我很高兴对 resultsList 进行循环,现在我将其发送到 gsp 视图。实际上,我从问题中的代码中删除了它,只是为了将我的问题集中在如何将 sql 转换为休眠状态。【参考方案2】:1) 如果它是从头开始开发的 Grails 应用程序(而不是基于遗留数据库结构),那么您可能应该已经拥有域类 Category
、Target
、UrlMetaData
(否则您将不得不手动或使用 db-reverse-engineer 插件创建它们)
2) 我假设Target
有一个字段Category category
和Category
有一个字段UrlMetaData urlMetaData
3) 要走的路可能是http://grails.org/doc/2.1.0/ref/Domain%20Classes/createCriteria.html,我会尝试为您的特定案例概述基础知识
4) 不确定 theDomain
的含义 - 可能是代码异味,以及接受来自客户端的 rlike
参数
5) 下面的代码根本没有经过测试——特别是我不确定嵌套条件内部的析取是如何工作的。但这可能是一个合适的起点;记录 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
干杯, 伊戈尔·西内夫
【讨论】:
谢谢伊戈尔!我编辑了原始帖子以包含数据库表和一些虚拟数据。在代码中修复了 domainName 的使用,并进一步解释了我最终要实现的目标。 我仍然不确定您是否已经拥有像Category
和 Target
这样的域类,或者您现在需要创建它们。
如果你有域类,那么你能告诉我建议的代码是否有帮助吗? (我认为根据您的数据从头开始构建测试应用程序对我来说是不切实际的 - 无论如何它都是不准确的)以上是关于grails:将 SQL 转换为域类的主要内容,如果未能解决你的问题,请参考以下文章