Grails querying model containing an enum set - grails

My domain class is
class RoomWantedAd{
Set<MateAgeRange> mateAgeRanges
static hasMany=[mateAgeRanges :MateAgeRange]
}
Her MateAgeRange is :
enum MateAgeRange {
TWENTIES('18-29')
,THIRTIES('30-39')
,FOURTIES("40-49")
,FIFTIES("50-59")
,SIXTIES("60+")
final String value
private MateAgeRange(String value) {
this.value = value
}
String toString() { value }
String getKey() { name() }
static belongsTo=[roomWanted:RoomWanted]
}
My problem is searching. In the search page, a person can select 0 or more values in [18-29, 30-39, 40-49, 50-59, 60+]. In the db, 0 or more values among [18-29, 30-39, 40-49, 50-59, 60+] are stored in field 'mateAgeRanges'.
Let db contains [30-39, 50-59] in 'mateAgeRange' field. Let in the search page, the user selects [18-29, 50-59, 60+]. Then the Ad corresponding to the above list must be returned. This is because at least one value in user's selection is present in the db list. How is it possible. Is it possible using an SQL query or grails GORM query.

you have to use exactly the same <g:select/> tag as you are using for create/update. Thus, you will see human readable values like THIRTIES in browser, but in the background the '30-39' values will be used.

Related

Attempting to map dates to index in ElasticSearch

I am using ElasticSearch and attempting to create an index with a class that has a dynamic type property in it. This property may have strings or dates in it. When indexing, I have been using the code below:
dynamic instance = MyObject.GetDynamicJson();
var indexResponse = client.Index((object) instance, i=>i
.Index("myIndex")
.Type("MyObject")
);
Here's the code for GetDynamicJson().
MyObject has only Name and Value as properties. (apologies, I've had issues in the past with Elastic choking on json without all the quotes, which I have escaped with \ characters):
String json = "{ \"Name\":\" + Name + "\",\"DateValue\":\"";
try {
var date = DateTime.parse(Value);
json += DateTime.ToString("yyyy/MM/dd HH:mm:ss Z") + "\", \"Value\":\"\"}";
} catch { //If the DateTime parse fails, DateValue is empty and I'll have text in Value
json += "\",\"Value\":\"" + Value + "\"}";
}
return json;
For some reason it doesn't seem to like the string in DateValue and I definitely don't know why it's leaving out that property entirely in the error:
For whatever reason, ElasticSearch is completely dumping the DateValue property, doesn't seem to see the DateValue property at all.
I'm getting the error:
{"name":"CreatedDate","value":"2017-11-07T13:37:11.4340238-06:00"}
[indices:data/write/bulk[s][p]]"}],"type":"class_cast_exception","reason":"org.elasticsearch.index.mapper.TextFieldMapper cannot be cast to org.elasticsearch.index.mapper.DateFieldMapper"},"status":500
Later note: I have changed the index creator method to update the mapping. I added a third field to the Object, so now it has properties: Name, Value, DateValue:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
Now, it is successfully mapping and creating a property each time, but it still seems to drop the property I am sending it in the json. It just sets them all to the default datetime: "dateValue": "0001-01-01T00:00:00". This is strange, because when making the dynamic instance I send to Elastic, I use only the MyObject.GetDynamicJson() method to build it. I no longer get the mapping error, but Elastic still seems oblivious to "dateValue":"some date here" in the object when it is set.
OK, I got rid of the dynamic object type (ultimately I wasn't actually getting data from the json method, I had a typo and Elastic was getting the original object directly - it's a wonder it was still handling it). So I let Elastic do the parse using its mapping. In order to do that, I first updated MyObject to include multiple properties, one for each type the incoming property could be (I am only handling text and dates in this case). For the DateValue property of MyObject, I have this:
public DateTime DateValue {
get
{
try
{
return DateTime.Parse(Value);
} catch
{
return new DateTime();
}
}
set
{
try {
DateValue = value;
} catch
{
DateValue = new DateTime();
}
}
}
Now, if Value is a date, my DateValue field will be set. Otherwise it'll have the default date (a very early date "0001-01-01T00:00:00"). This way, I can later search both for text against that dynamic field, or if a date is set, I can do date and date range queries against it (technically they end up in two different fields, but coming from the same injested data).
Key to this is having the index mapping setup, as you can see in this method from the question:
public static void CreateRecordsIndex(ElasticClient client)
{
client.CreateIndex("myIndex", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(x => x
.Map<MyObject>(m => m.AutoMap())));
}
In order to recreate the index with the updated MyObject, I did this:
if (client.IndexExists("myIndex").Exists)
{
client.DeleteIndex("myIndex");
CreateRecordsIndex(client); //Goes to the method above
}

Grails 3.2 - List field names in domain class that are not nullable

How can I get a list of field names for a domain class that are not nullable?
For instance, in the following domain:
class MyDomain {
String field1
String field2
String field3
String field4
static constraints = {
field2 nullable: true
field3 nullable: true
}
}
How can I get back the list ['field1','field4'] in a controller?
I'm validating rows in a CSV, and some of the row information is different from what is stored in the domain, so it would be preferable to get a List of String names rather than bind to a command object with exclusions.
You can use the constrainedProperties. It gives all the constraints of the particular domain class.
And now you want only the non-nullble constraints then filter out the result for it.
Example :
MyDomain.constrainedProperties.findResults { it.value.nullable ? null : it.key }
Output :
['field1','field4']
For grails 2.x users :
MyDomain.getConstraints().findResults { it.value.nullable ? null : it.key }
You need to use the PersistentEntity API
Set<String> propertyNames = [] as Set
for (PersistentProperty prop: MyDomain.gormPersistentEntity.persistentProperties) {
if (!prop.mapping.mappedForm.nullable) {
propertyNames.add(prop.name)
}
}
You may have to exclude things like version or timestamp properties depending on what you want.

Select all records of a List<T> relationship into Results<T>?

I'm binding a table view to a collection of Results<Person> this result set can be filtered but normally it is not. The problem is that when I try to bind - say; person.children to the table view which is of type List<Person>. If I don't filter it, I don't get a Results<Person> type, so I need to have two different properties to store the dataset for the table. One for Results, one for List.
My question is... is there a way to return all records from a List as Results? Something similar to .all()? I have tried to use an empty NSPredicate, but this is not allowed and a property name must be specified. I want my function to be generic enough that it can be called on any List to obtain all Results. I don't want to have to specify say... .filter("firstName != ''") just to get all the results.
I have currently implemented something like this... But I'm curious if there's a better way.
extension List {
func all() -> Results<T> {
let primaryKey = T.primaryKey() ?? "id"
return self.filter("\(primaryKey) != ''")
}
}
EDIT: Looks like this implementation of All will not work for Objects with a primary key of type Int. Is there anyway to check an object's primary key type?
Using TRUEPREDICATE seems to work!
extension List {
/// Returns an Results object for all Objects in the List.
func all() -> Results<T> {
return self.filter("TRUEPREDICATE")
}
}

Entity Framework is not returning the proper data. It is repeating data from a single record

Using MVC 4 with EF code First.
When doing linq to EF selects statements, the collections are being populated with what seems like the last record's data. And what's weirder, only some of the properties are repeated where others are not. It is best to show you by example:
Using this query returns the proper data:
var orders = db.Orders.ToList();
OrderID OrderTotal Name
1 215.00 Bob
2 415.00 Mark
3 315.50 Ralph
When I filter the Orders entity by a SubscriberID, which is a foreign key, like so:
var orders = db.Orders.Where(s => s.SubscriberId == 2).ToList();
The data end up looking like this:
1 315.50 Bob
2 315.50 Mark
3 315.50 Ralph
Notice how the OrderTotal is repeated but the names stay the same. Please note that this is not a view issue. When I look at the data in the collection while debugging in the controller, this is what I see. This does not appear to be the only place this is happening. I am seeing something similar with more complicated models - but I thought I'd start with the simplest sample. Thanks!
The problem was caused when I was setting default values on my models. Apparently using static was incorrect. So:
[ReadOnly(true)]
[Display(Name = "Sub total")]
private static decimal _OrderSubTotal = 0;
public decimal OrderSubTotal { get { return _OrderSubTotal; } set { _OrderSubTotal = value; } }
Should be written as
[ReadOnly(true)]
[Display(Name = "Sub total")]
private decimal _OrderSubTotal = 0;
public decimal OrderSubTotal { get { return _OrderSubTotal; } set { _OrderSubTotal = value; } }

accessing auto-generated fields and querying

I have the following piece of code in ItemController.groovy
def list = {
params.max = 60
def storeYYId = params.id
[itemInstanceList: Item.list(params), itemInstanceTotal: Item.count()]
}
I have the following in Item.groovy:
class Item {
String itemName
static belongsTo = [store:Store]
static constraints = {
itemName(blank:false)
storeId()
}
}
This gives me an error since it tells me that there is no storeId property, but there is, since store_id is a foreign key to the Store table in the corresponding database.
Question1. How do I tell grails to let me access the properties of domains that are autogenerated by GORM, like the id and storeId in this case?
Question2. What code should I write in my ItemController.groovy in my list action, in order to retrieve only a list of items where the storeId == storeYYId ?
Question1. How do I tell grails to let me access the properties of
domains that are autogenerated by GORM, like the id and storeId in
this case?
You should be able to access autogenerated properties in exactly the same way as you access properties that you define. The reason you're getting an error is because Grails does not automatically generate a storeId property for the Item class, the only properties it will autogenerate are version and id (for both Item and Store).
Question2. What code should I write in my ItemController.groovy in my
list action, in order to retrieve only a list of items where the
storeId == storeYYId ?
You'll need to write either a HQL or criteria query to retrieve these items. The criteria query would look something like this (untested)
// Get all items that have storeId = 6
def storeId = 6
def items = Item.withCriteria {
store {
eq('id', storeId)
}
}

Resources