what the urls mapping processing order for the grails framework
"/$object/$id/$collection"
"/$object/$id/bar/list"
"/foo/$id/bar/list"
Which one will execute first. I'm getting unexpected behavior where the generic mapping seems to execute first
what do you want to achieve ?
/$object/$id/bar/list maps /foo/$id/bar/list to.
But if you want any custom behavior for foo you can set constrainst for first mapping, e.g.:
/$object/$id/bar/list {
controller = "bar"
action = "list"
constraints {
object(matches: /.*[^fo].*/)
}
}
"/foo/$id/bar/list"
Regexp is not ideal but it shows basic principles
i believe the order will be
/foo/$id/bar/list // 1 value to calc
/$object/$id/bar/list // 2 value(s) to calc
/$object/$id/$collection // all unknown values
grails documentation states the strongest will take precedent, meaning whatever does not have to be calculated at runtime.
Related
Grails gives the possibility of creating simple string/value map properties section "Maps of Objects", first paragraph.
I was wondering, is there a way to later query the domain class (using Gorm dynamic finders, criterias or HQL) using the map property as part of the query (i.e adding a condition for the key X to have the value Y)?
After playing with it a bit and almost give up, I discovered the map syntax to (surprisingly) work in HQL. Assuming the class looks like:
class SomeClass {
Map pairKeyProperty
}
You can build queries that look like the following:
select * from SomeClass sc where sc.pairKeyProperty['someKey'] = 'someValue' and sc.pairKeyProperty['someOtherKey'] = 'someOtherValue'
Pretty neat! I still would prefer to use criterias as they are much cleaner to compose, but they seem to not support the same syntax (or I couldn't find it).
I created a sample app in GitHub:
https://github.com/deigote/grails-simple-map-of-string-value-pairs
It can be visisted at:
http://grails-map-of-string-pairs.herokuapp.com/
The form above uses a cross join. To enforce an inner join use
join sc.pairKeyProperty pk1 on index(pk1) = 'someKey'
where 'someValue' in elements(pk1)
I'm new to grails, but have previous experience using .net with c# and linq to query databases.
I'm trying to filter a list of objects by optional items using a multiple selection drop box. So to the controller I will get a list of parameters some of which will be null. So I want to have something akin to
DailyProduction.Where(x => loaction.contains(x.location)).Select().ToList().
However, it doesn't see quite as simple with in groovy and grails.
Here is what I've tried:
def filteredList = DailyProductionReport.createCriteria()
def results = filteredList.list {
if(params.locationSelect != null)
'in'("location", [params.locationSelect.each{ it != null}])
}
But I get a Runtime Exception that says:
Class:
java.lang.ClassCastException
Message:
[Ljava.lang.String; cannot be cast to java.lang.String
I've tried look over different forums with out any luck. I'm almost at my wits end. If any groovy master can shed some light on things for me I'd greatly appreciate it.
Thanks
It looks like your problem might be
[params.locationSelect.each{ it != null }]
each is used for iteration and the resulting expression is just the list being iterated over. Also, the square brackets nest that list in another list. You probably want
'in'('location', params.locationSelect.findAll { it != null })
In this particular case, you can also just use the identity closure since "groovy truth" for objects is the same as testing for null:
'in'('location', params.locationSelect.findAll())
Users of my application have the possibility of choosing some values from list. The values for that list are in simple domain class, Foo, which looks like that:
class Foo{
String name
static mapping = {
id name: 'name', generator: 'assigned'
version: false
}
}
Foo looks the same for every language my app uses. In another class I have a constraint saying that Bar must be in list of Foo. Sometimes user doesn't know what to choose, so he may choose something like "I'm not sure" (so this option should be in list to to meet the inList constraint). Thing is, "I'm not sure" is written differently in different languages. How can I append this value based on current messages to inList constraint?
In your controller you could do:
def theList = foo.list().name // Get any array of strings.
// If you actually need > 1 field then you probably need to
// put the g.message below in a map
theList << g.message(code:"im.not.sure")
I don't believe inList constraint will help you here - it's designed for a simpler use case than yours.
I'd add a method to the class getLanguages() that handles this, and then since you seem to be interested in validation, write a custom validator to make sure right values are saved.
I'm attempting to pull up all entities that have a name that doesn't partially match a given string.
MyEntity.findAllByNameNotLike('bad%')
This gives me the following error:
No such property: nameNot for class: MyEntity
Possible solutions: name" type="groovy.lang.MissingPropertyException">
I had a quick look at the criteria style but I can't seem to get that going either,
def results = MyEntity.withCritieria {
not(like('name', 'bad%'))
}
No signature of method: MyEntity.withCritieria() is applicable for argument types: (MyService$_doSomething_closure1)
Ideally I would like to be able to apply this restriction at the finder level as the database contains a large number of entities that I don't want to load up and then exclude for performance reasons.
[grails 1.3.1]
I've worked out how to do this using withCriteria, the not should have been a closure of its own.
def results = MyEntity.withCritieria {
not {
like('name', 'bad%'))
}
}
The problem I initially had using withCriteria was that I was trying to test this as a unit test, which works fine with the dynamic finders, but not with the criteria API (as far as I can tell).
(I'll leave this unanswered for a day to see if anyone has a better solution, otherwise I'll accept my answer)
I'm working on an application at the moment in ASP.NET MVC which has a number of look-up tables, all of the form
LookUp {
Id
Text
}
As you can see, this just maps the Id to a textual value. These are used for things such as Colours. I now have a number of these, currently 6 and probably soon to be more.
I'm trying to put together an API that can be used via AJAX to allow the user to add/list/remove values from these lookup tables, so for example I could have something like:
http://example.com/Attributes/Colours/[List/Add/Delete]
My current problem is that clearly, regardless of which lookup table I'm using, everything else happens exactly the same. So really there should be no repetition of code whatsoever.
I currently have a custom route which points to an 'AttributeController', which figures out the attribute/look-up table in question based upon the URL (ie http://example.com/Attributes/Colours/List would want the 'Colours' table). I pass the attribute (Colours - a string) and the operation (List/Add/Delete), as well as any other parameters required (say "Red" if I want to add red to the list) back to my repository where the actual work is performed.
Things start getting messy here, as at the moment I've resorted to doing a switch/case on the attribute string, which can then grab the Linq-to-Sql entity corresponding to the particular lookup table. I find this pretty dirty though as I find myself having to write the same operations on each of the look-up entities, ugh!
What I'd really like to do is have some sort of mapping, which I could simply pass in the attribute name and get out some form of generic lookup object, which I could perform the desired operations on without having to care about type.
Is there some way to do this to my Linq-To-Sql entities? I've tried making them implement a basic interface (IAttribute), which simply specifies the Id/Text properties, however doing things like this fails:
System.Data.Linq.Table<IAttribute> table = GetAttribute("Colours");
As I cannot convert System.Data.Linq.Table<Colour> to System.Data.Linq.Table<IAttribute>.
Is there a way to make these look-up tables 'generic'?
Apologies that this is a bit of a brain-dump. There's surely imformation missing here, so just let me know if you'd like any further details. Cheers!
You have 2 options.
Use Expression Trees to dynamically create your lambda expression
Use Dynamic LINQ as detailed on Scott Gu's blog
I've looked at both options and have successfully implemented Expression Trees as my preferred approach.
Here's an example function that i created: (NOT TESTED)
private static bool ValueExists<T>(String Value) where T : class
{
ParameterExpression pe = Expression.Parameter(typeof(T), "p");
Expression value = Expression.Equal(Expression.Property(pe, "ColumnName"), Expression.Constant(Value));
Expression<Func<T, bool>> predicate = Expression.Lambda<Func<T, bool>>(value, pe);
return MyDataContext.GetTable<T>().Where(predicate).Count() > 0;
}
Instead of using a switch statement, you can use a lookup dictionary. This is psuedocode-ish, but this is one way to get your table in question. You'll have to manually maintain the dictionary, but it should be much easier than a switch.
It looks like the DataContext.GetTable() method could be the answer to your problem. You can get a table if you know the type of the linq entity that you want to operate upon.
Dictionary<string, Type> lookupDict = new Dictionary<string, Type>
{
"Colour", typeof(MatchingLinqEntity)
...
}
Type entityType = lookupDict[AttributeFromRouteValue];
YourDataContext db = new YourDataContext();
var entityTable = db.GetTable(entityType);
var entity = entityTable.Single(x => x.Id == IdFromRouteValue);
// or whatever operations you need
db.SubmitChanges()
The Suteki Shop project has some very slick work in it. You could look into their implementation of IRepository<T> and IRepositoryResolver for a generic repository pattern. This really works well with an IoC container, but you could create them manually with reflection if the performance is acceptable. I'd use this route if you have or can add an IoC container to the project. You need to make sure your IoC container supports open generics if you go this route, but I'm pretty sure all the major players do.