Tuesday, March 29, 2011

Multi-Associative GORM Criteria with Projections

I have three domain classes: Lead, Submission and BuyerLog:

class Lead {
static hasMany = [ submissions: Submission ]
Date dateCreated
// ...
}
class Submission {
static belongsTo = [ lead: Lead ]
static hasMany = [ buyerLogs: BuyerLog ]
Lead lead
// ...
}
class BuyerLog {
static belongsTo = [ submission: Submission ]
Submission submission
String leadBuyer
// ...
}

I have a need to get the number of duplicate leads which share the same leadBuyer (in the BuyerLog domain class). Here is the SQL:

SELECT count(l.id)
FROM lead AS l, submission AS s, buyerLog as bl
WHERE l.id = s.leadId
AND s.id = bl.submissionId
AND bl.leadBuyer = $buyerName
AND l.id != $lead.id
AND l.dateCreated::date > $daysAgo
view raw blogPost2.sql hosted with ❤ by GitHub

I want to do this using GORM / Criteria Builder. Here's my final code:

/**
* Count duplicate submissions within 45 days
* SELECT count(l.id)
* FROM lead AS l, submission AS s, buyerLog as bl
* WHERE l.id = s.leadId
* AND s.id = bl.submissionId
* AND bl.leadBuyer = $buyerName
* AND l.id != $lead.id
* AND l.dateCreated::date > $daysAgo
*/
protected def Boolean isDuplicateSubmission(Lead lead, ArrayList<String> buyerNames) {
def isDuplicate = false
def daysAgo = new Date() - 45
def cnt = Lead.withCriteria {
not {
idEq(lead.id)
}
and {
le('dateCreated', daysAgo)
submissions {
buyerLogs {
inList('leadBuyer', buyerNames)
}
}
}
projections {
rowCount()
}
}
return (cnt > 0)
}

Thanks to schmolly159 on the #grails freenode IRC channel for the examples and continued help.

4 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Manuel, yes that is correct. I fixed it. Thanks.

    ReplyDelete
  3. Hey Eric,

    Looks very cool, but have you thought about perhaps writing this as a named query inside your domain class? Encapsulating this in your model is a very tidy way of doing this sort of thing.

    Coincidentally I wrote a blog post about this sort of thing too last week! Check out my article here:
    http://mycodesnippets.com/2011/03/20/named-queries-with-projections-in-grails/

    Cheers,
    Marco.

    ReplyDelete
  4. Sorry, I removed the previous comment because I realized it had a typo. :)

    ReplyDelete