how can i add a integer list in grails domain class - grails

I have created a domain class as given below, which contains an int and list of Integer properties.
class User {
int UserId
List<Integer> UserFriendsId
static constraints = {
}
User() {
this.UserId = 21
this.UserFriendsId=[1,2,3]
}
}
The table generated for this domain class while saving is as follows
mysql> select * from user;
+----+---------+---------------------+
| id | version | UserId |
+----+---------+---------------------+
| 1 | 0 | 21 |
| 2 | 0 | 21 |
| 3 | 0 | 21 |
+----+---------+---------------------+
3 rows in set (0.00 sec)
column for userFriendsId (ie: for list of integers) is not generated in this table user.
so how can solve this issue or can add list of integer in grails domain class.

The UserFriendsId List should be mapped as a GORM basic collection type and not simply be a list in the User domain class:
class User {
int userId
static hasMany = [userFriendsIds: Integer]
static mapping = {
userFriendsIds joinTable: [name: "user_id", column: "friend_id", type: Integer]
}
static constraints = {
}
User() {
}
}

Why not just make UserFriendsId a comma separated String?
class User {
int UserId
String UserFriendsId
static constraints = {
}
User() {
this.UserId = 21
this.UserFriendsId = "1,2,3"
}
}
Then:
for (userId in UserFriendsId.get(21).split(','))
{
println userId.toInteger()
/// Or do whatever ...
}

Related

Specflow scenario outline examples table - to object?

I am using specflow and I have a rather large table in my examples:
it has around 14 fields.
is there a better way of passing all of those filds into a method that is item1 and item2 and item4
I can see that there is a create set method, but this doesn't seem to cater for examples, and only in step....well steps.
is there a way to pass the data in an object rather than sending 14 strings?
Hope that makes sense.
Ta,
Steve
** Edit ** adding an example
Here is the headers for my exmaple file
| propLocation | locPropToBuy | propertyType | newBuild | appsLiveProprty | ownershipType | purchPrice | totLoanAmount | intOnlyAmount | prefLoanTermYrs | prefLoanTermMths |
the method generated for this will look like this:
[When(#"the user provides input for the Property and Loan Requirements Section (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*) and (.*)")]
public void WhenTheUserProvidesInputForThePropertyAndLoanRequirementsSectionEnglandAndYesAndTerracedHouseAndYesAndYesAndStandardAndAndAndAndAndAndAndAndSAnd(string propLocation,
string locPropToBuy, string propertyType, string newBuild, string legalOwnership,
string ownershipType, string equityShreScheme, string purchPrice, string fullMarketVal,
string termShareLoanYrs, string termShareLoanMths, string totLoanAmount,
string intOnlyAmount, string prefLoanTermYrs, string prefLoanTermMths)
Although I will eventually change the coded values to (.*) etc.
It would be easier for me if I could just pass an object or a list of all the values rather than long instances of strings.
Take a look at Specflow tables
When the user provides input for the Property and Loan Requirements Section
| Key | Value |
| propLocation| NYC |
| locPropToBuy| House123 |
| propertyType| House |
| newBuild | Nope |
and so on and so on
Create a new class with PropertyLoanData and then interpret the table
public class PropertyLoanData
{
public string propLocation { get; set; }
public string locPropToBuy { get; set; }
public string propertyType { get; set; }
public string newBuild { get; set; }
}
.
[When(#"the user provides input for the Property and Loan Requirements Section
public void WhenUserprovidesinputforPropertyAndLoanSection(Table table)
{
var proploandata = table.CreateInstance<PropertyLoanData>();
driver.FindElement(By.Id("propLocation")).SendKeys(proploandata.propLocation);
driver.FindElement(By.Id("locPropToBuy")).SendKeys(proploandata.locPropToBuy);
driver.FindElement(By.Id("propertyType")).SendKeys(proploandata.propertyType);
driver.FindElement(By.Id("newBuild")).SendKeys(proploandata.newBuild);
}

Trying to perform soft delete of entity with relations causes exception

Recently, I implemented soft delete for most of my entities in the app (at least the ones I needed).
The implementation looks like this:
Goal.groovy
class Goal {
String definition;
Account account;
boolean tmpl = false;
String tmplName;
Goal template
Timestamp dateCreated
Timestamp lastUpdated
Timestamp deletedAt
static belongsTo = [
account: Account,
template: Goal
]
static hasMany = [perceptions: Perception, sessions: RankingSession]
static mapping = {
autoTimestamp true
table 'goal'
definition type: 'text'
tmplName column: '`tmpl_name`'
perceptions sort:'title', order:'asc'
dateCreated column: 'date_created'
lastUpdated column: 'last_updated'
deletedAt column: 'deleted_at'
}
...
def beforeDelete() {
if (deletedAt == null) {
Goal.executeUpdate('update Goal set deletedAt = ? where id = ?', [new Timestamp(System.currentTimeMillis()), id])
}
return false
}
...
Perception.groovy
class Perception {
String title
String definition
Goal goal
Timestamp dateCreated
Timestamp lastUpdated
Timestamp deletedAt
static hasMany = [left: Rank, right: Rank]
static mappedBy = [left: "left", right: "right"]
static belongsTo = [goal: Goal]
static namedQueries = {
notDeleted {
isNull 'deletedAt'
}
}
static mapping = {
autoTimestamp true
table 'perception'
definition type: 'text'
dateCreated column: 'date_created'
lastUpdated column: 'last_updated'
deletedAt column: 'deleted_at'
}
static constraints = {
title blank: false, size: 1..255
definition nullable: true, blank: true, size: 1..5000
goal nullable: false
lastUpdated nullable: true
deletedAt nullable: true
}
/**
* before delete callback to prevent physical deletion
*
* #return
*/
def beforeDelete() {
if (deletedAt == null) {
Perception.executeUpdate('update Perception set deletedAt = ? where id = ?', [new Timestamp(System.currentTimeMillis()), id])
}
return false
}
}
Rank.groovy
class Rank {
Perception left
Perception right
Integer leftRank
Integer rightRank
RankingSession session
static belongsTo = [session: RankingSession]
static mapping = {
table 'rank'
}
static constraints = {
leftRank range: 0..1, nullable: true
rightRank range: 0..1, nullable: true
left nullable: false
right nullable: false
session nullable: false
}
}
My problem happens on deletion (logical deletion). I perform the deletion through service class the following way:
GoalService.groovy
#Transactional
class GoalService {
/**
* Deletes goal
*
* #param goal
* #return
*/
def deleteGoal(Goal goal) {
if (goal.tmpl == true) {
throw new ValidationException("Provided object is a template!")
}
def perceptions = Perception.notDeleted.findAllByGoal(goal)
for (perception in perceptions) {
perception.delete()
}
goal.delete()
}
}
I have a use-case, which work under one condition and trows an exception under another.
#1 Existing Goal with number of assigned perceptions to it. Deletion works as expected: The Goal and Perceptions are marked as deleted.
#2 Goal with Perceptions + Number of Rank objects linked to Perceptions.
When I am trying to delete such a goal, I am getting an exception:
Error 2015-03-23 14:52:10,294 [http-nio-8080-exec-9] ERROR spi.SqlExceptionHelper - Column 'left_id' cannot be null
| Error 2015-03-23 14:52:10,357 [http-nio-8080-exec-9] ERROR errors.GrailsExceptionResolver - MySQLIntegrityConstraintViolationException occurred when processing request: [POST] /triz/rrm/goal/1/delete - parameters:
SYNCHRONIZER_TOKEN: 57fda8f2-8025-45e0-ac60-592234f54ef1
SYNCHRONIZER_URI: /triz/rrm/goals
Column 'left_id' cannot be null. Stacktrace follows:
Message: Column 'left_id' cannot be null
Line | Method
->> 411 | handleNewInstance in com.mysql.jdbc.Util
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
| 386 | getInstance in ''
| 1041 | createSQLException in com.mysql.jdbc.SQLError
| 4237 | checkErrorPacket in com.mysql.jdbc.MysqlIO
| 4169 | checkErrorPacket . in ''
| 2617 | sendCommand in ''
| 2778 | sqlQueryDirect . . in ''
| 2834 | execSQL in com.mysql.jdbc.ConnectionImpl
| 2156 | executeInternal . in com.mysql.jdbc.PreparedStatement
| 2441 | executeUpdate in ''
| 2366 | executeUpdate . . in ''
| 2350 | executeUpdate in ''
| 129 | doCall . . . . . . in triz.rrm.RrmGoalController$_delete_closure5
| 127 | delete in triz.rrm.RrmGoalController
I've already tried everything, including:
physically dropped all constraints
used "cascade: 'save-update'" on relationships
Nothing helps, the only thing I can understand is the fact that it is related to cascading, but why is GORM trying to cascade 'delete' if in reality I am updating the objects?
You are getting the exception because Rank has a reference to Perception, but you did not specify belongsTo on either side.
You have this in Rank:
Perception left
That is why you are getting Column 'left_id' cannot be null. Stacktrace follows....
So to solve the problem either delete rank objects having r/ship with each perception you are deleting or specify belongsTo = [left: Perception] with in Rank.

How to distinct list from createCriteria?

I have a problem ..to distinct my list..this is my code..
domain :
class City {
String city
static constraints = {
city(blank:false,unique:false)
}
}
class Financial {
String financial
String description
static constraints = {
financial(blank:false,unique:false)
}
}
class Bank {
Financial financial
City city
static constraints = {
financial(blank:false)
}
}
I want to create a list from domain bank, with this code :
def index= {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
if(!params.sort && !params.order)
{
params.sort = "city"
params.order = "desc"
}
def c = Bank.createCriteria()
def results = c.list(params)
{
if(params.financial)
{
financial{
ilike("financial", "%${params.financial}%")s
}
}
}
[bankdetaillist: results,bankdetaillisttotal:results.totalCount, financial: params.financial?:""]
}
If i create a bank , example..
Table bank :
id | version | city | financial
-------------------------------
0 | 0 | 1 | 1
1 | 0 | 5 | 1
From this case, we know the bank with financial 1 have many cities...
And I want to show it to list with a distinct bank from field financial.
A createCriteria seems a bit overkill for what you want. What about:
Financial finRecord = Financial.findByFinancial(params.financial)
List<Bank> banksForFin = Bank.findAllByFinancial(finRecord,[sort: "city", order: "desc"])

Best practice for selecting two columns

I have some query like below
var email= (from c in dataContext.tblC
where (c.AA == aa)
select c.email).ToList();
string emails = email.Aggregate((a, b) => a + "," + b);
Now I need another column SecEmail, I can't just (...select c.email, c.SecEmail).ToList().
Any suggestion for I can get list like (email1, SecEmail1, email2, email3, SecEmail3, email4...)
if you're working with dynamic objects:
var email = (from c in dataContext.tblC
where c.AA == aa
select new {
email = x.email,
secemail = c.secEmail,
// ...
}).ToList(); // IList<dynamic> & IDE will know what properties
// you supplied in the `select new { }`
Otherwise build a model and populate it:
public class SelectModel
{
public String email { get; set; }
public String secemail { get; set; }
}
var email = (from c in dataContext.tblC
where c.AA == aa
select new SelectModel {
email = x.email,
secemail = c.secEmail,
// ...
}).ToList(); // IList<SelectModel>
If you want the returned rows turned in to an email to header:
var email = String.Join(", ", (
from c in dataContext.tblC
where c.AA == aa
select c.email
).AsEnumerable());
Which would make:
+------------------+
| email |
|------------------|
| foo#contoso.com |
| bar#contoso.com |
| baz#contoso.com |
+------------------+
Turn in to:
foo#contoso.com, bar#contoso.com, baz#contoso.com
Multi-column concat:
var email = (from c in dataContext.tblC
where c.AA == AA
select new { email = c.email, secEmail = c.secEmail }).AsEnumerable();
var to = String.Join(", ",
email.Select(x => x.email)
.Concat(email.Select(y => y.secEmail))
// .Concat(eail.Select(y => x.thirdColumn))
// ...
);

grails: converting SQL into domain classes

I am developing a GRAILS application (I'm new to GRAILS and inherited the project from a previous developer). I'm slowly getting a small grasp for how GRAILS operates and the use of DOMAIN classes, hibernate etc. The MySQL db is hosted on Amazon and we're using ElasticCache.
Do any of you more knowledgeable folks know how I can go about converting the following SQL statement into domain classes and query criteria.
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 )
}
The tables are as follows (dummy data):
[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
domain classes
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)
}
}
Basically, a url from url_meta_data can be associated to many categories. So in essence what I'm trying to achieve should be a relatively basic operation...to return all the urls for the search-term 'car', their weight(i.e importance) and where the ugc_flag is not 1(i.e the url is not user-generated content). There are 100K + of records in the db and these are imported from a third-party provider. Note that all the URLs do belong to my client - not doing anything dodgy here.
Note the rlike I've used in the query - I was originally using ilike %searchterm% but that would find categories where searchterm is part of a larger word, for example 'caravan') - unfortunately though the rlike is not going to return anything if the user requests 'cars'.
I edited the code - as Igor pointed out the strange inclusion originally of 'domainName'. This is an optional parameter passed that allows the user to filter for urls of only a certain domain (e.g. 'example.com')
I'd create an empty list of given domain objects,
loop over the resultsList, construct a domain object from each row and add it to a list of those objects. Then return that list from controller to view. Is that what you're looking for?
1) If it's a Grails application developed from a scratch (rather than based on a legacy database structure) then you probably should already have domain classes Category, Target, UrlMetaData (otherwise you'll have to create them manually or with db-reverse-engineer plugin)
2) I assume Target has a field Category category and Category has a field UrlMetaData urlMetaData
3) The way to go is probably http://grails.org/doc/2.1.0/ref/Domain%20Classes/createCriteria.html and I'll try to outline the basics for your particular case
4) Not sure what theDomain means - might be a code smell, as well as accepting rlike arguments from the client side
5) The following code hasn't been tested at all - in particular I'm not sure how disjunction inside of a nested criteria works or not. But this might be suitable a starting point; logging sql queries should help with making it work ( 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
}
Possibly the or restriction works better when written explicitly
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
}
Cheers,
Igor Sinev

Resources