i have to create a domain class object which has a nullable attribute. This Creating is in an extansion of a primitive class.
For example: Domainclass
Meeting({required String id, required Datetime date, Example? example})
behind Example is an class like so: Example(String value)
MeetingPrimitive.dart:
extension MeetingPrimitiveX on Meeting {
Meeting toDomain() {
return Meeting(
id: id,
date: date,
example: example == null ? null : Example(example)
}
}
My question is, how can i simplify this:
example == null ? null : Example(example)
'''
thanks in advance
You generally can't.
You can change it in various ways, but nothing is more direct than what you have here.
One variant would be:
extension DoWith<T> on T {
R doWith<R>(R Function(T) action) => action(this);
}
With that, you can write:
example?.doWith(Example.new)
to conditionally call the Example.new constructor (tear-off of the unnamed constructor) if example is non-null.
Slightly shorter, requires a helper function, and ... isn't actually more readable IMO.
Related
I am creating a basic CRUD application with a Person entity:
class Person {
public int Age;
...
public int getAge() {
return this.Age;
}
public void setAge(int AgeToSet) {
this.Age = AgeToSet;
}
}
I have a controller and I want to retrieve all Persons with an age of 20:
def filter = {
def c = Person.createCriteria();
def persons = c.list{
eqProperty("Age", "20");
}
[persons: persons];
}
But this is not working and is, instead, giving me the error:
ERROR StackTrace - Full Stack Trace:
org.hibernate.QueryException: could not resolve property: Age of: project.Person
at org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:62)
What could be the problem?
Three things:
Your Age needs to start with lowercase: age.
Your criteria is wrong, you want to use eq. eqProperty compares two properties, but you only need one and a value.
Your comparision must be with an int, like this: eq("myage", 20).
Since this query is so simple, you may want to just use a DynamicFinder: http://gorm.grails.org/6.0.x/hibernate/manual/index.html#finders
With a Dynamic Finder, you could simplify the query to:
def persons = Person.findAllByAge(20)
Just a suggestion. I use Dynamic Finders as my primary query method. If I need a query that is more complex, I'll resort to a .createCriteria and then a .executeQuery which takes HQL.
I have a domain class
class Url {
UUID id
String url
static hasMany = [
indications:UrlIndication
]
...
}
And
class UrlIndication {
UUID id
String name
static belongsTo = Url
...
}
I want to choose urls so that it has all the necessary UrlIndication elements in a given list indicationsId.
For that I use an association and criteria like this one:
indications {
and {
indicationsId.each{
indication->
eq ('id',UUID.fromString(indication as String))
}
}
}
However, all I got is an empty result. Can you suggest any modifications/ other methods so that I can do this? Thanks in advance
Your query returned an empty list because it's the equivalent of the expression (pseudo-code): if 1 = 1 and 1 = 2 and 1 = 3
Such an expression would always be false. in or inList would not work for the reason #innovatism described.
In theory, Criteria's eqAll() or HQL's = ALL would work. But, I don't know for sure because I could not get either one to work.
What will work is to use inList to return a subset of Urls: those which contain at least one of the UrlIndication IDs. Then use Groovy's containsAll() to finish the job.
def ids = indicationsId.collect { UUID.fromString(it as String) }
Url.createCriteria()
.buildCriteria {
indications {
inList 'id', ids
}
}
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
.findAll {
it.indications.id.containsAll(ids)
}
Since the query has the potential to return duplicate Url instances, the ResultTransformer is set to return a unique list.
Finally, findAll() is used along with containsAll() to filter the list further.
Using eqAll (maybe)
Something like the following might work. Something funky is going on with Grails' HibernateCriteriaBuilder that causes the eqAll method to look up properties in the root entity; completely ignoring the sub criteria. So the following uses Hibernate directly. It didn't work for me, but it's as close as I could get. And it gave me a head-ache!
Url.createCriteria().buildCriteria {}
.createCriteria('indications', 'i')
.add(org.hibernate.criterion.Property.forName('i.id').eqAll(org.hibernate.criterion.DetachedCriteria.forClass(UrlIndication)
.add(org.hibernate.criterion.Restrictions.in('id', ids))
.setProjection(org.hibernate.criterion.Property.forName('id'))
))
.setResultTransformer(org.hibernate.Criteria.DISTINCT_ROOT_ENTITY)
.list()
The problem I had is I could not get Restrictions.in to work. Restrictions.eq works fine.
the in clause should do:
indications {
'in' 'id', indicationsId.collect{ UUID.fromString indication.toString() }
}
I need to compare several domain class objects while they are still unsaved, however, I always keep getting a false result from the comparison. Turns out even the following comparison will return false:
new DomainClass().equals(new DomainClass())
Since both are brand new objects they should both have identical data and should be equal to each other. Unfortunately the equals method (or the == operator) returns false. Is there another correct way of performing this comparison?
Your code same with this:
a = new DomainClass();
b = new DomainClass();
a.equals(b)
So clearly the test must return false as far as a and b are not referencing same object.
If you want value based comparing:
Iterate over the fields and compare them one by one
Or check here for a more formal way of doing it.
you can use 'spaceship operator' (<=>) which work like compareTo()
or you can override equals() method in your DomainClass that make able to use this code
new DomainClass().equals(new DomainClass())
to override equals() you can use #EqualsAndHashCode annotation
this annotation automatically generate equals() and hashcode() methods
So, you class will look like this:
#EqualsAndHashCode
class DomainClass(){
String field1
String filed2
etc
}
and your generated equals method will look like this:
public boolean equals(java.lang.Object other)
if (other == null) return false
if (this.is(other)) return true
if (!(other instanceof DomainClass)) return false
if (!other.canEqual(this)) return false
if (field1 != other.field1) return false
if (field2 != other.field2) return false
// etc
return true
}
For more details look at this http://groovy.codehaus.org/api/groovy/transform/EqualsAndHashCode.html
I wanted to set a value to a field in domain class.
For example,
class Example {
String name
String lastName
}
Now, from response I'm getting domain name, object instance id, field name and value. I have to set the value to the field in domain class.
Here I got the values as
domainName = 'Example'
instanceId = 1
fieldName = 'name'
valueToSet = 'XYZ'
So how should I set value to the field name? May be this is simple but I'm a new with grails and groovy.
Based on the domain name, a new domain instance has to be created at runtime. For this to happen, grailsApplication has to be injected. Here is a sample which can be modeled after in Controller or a Service class:
class SomeService {
def grailsApplication
def someMethod(String domainName, long instanceId,
String fieldName, def valueToSet) {
Class domainClazz = grailsApplication.domainClasses.find {
it.clazz.simpleName == domainName
}.clazz
def domainInstance = domainClazz.get( instanceId )
domainInstance."$fieldName" = valueToSet
domainInstance.save()
}
}
You can populate a Grails domain class by assigning a map to its properties, for example from the params in the controller (using that handy automatic binding). E.g.:
ded example=new Example()
example.properties=params
So you can see from this that the domain object can be treated as a set of properties. Which means you can use strings for keys, so you might have something like:
example['name']='XYZ'
I don't know whether that's what you're asking but I hope it helps.
I have a results view that displays a list of items.
In some cases, I want to display items where one field matches the query argument. In other cases, I want to display items where another field matches the query argument. And so on.
How can I provide arguments to my controller/view so that it knows what kind of results to get? I could write multiple controllers, but then I get the error that "Type 'MyType' already defines a member called 'MyMethod' with the same parameter type."
Ideally, I could find a way to do this without creating additional routes. Is this possible?
From what I understand from your question you want to do the following:
Reutilize a view, so that you don't have to make one for each query.
Use the same method name on a controller so that you don't have a different url for each query.
You could add an extra parameter to your method so that you can perform a different query depending on the value of the extra parameter:
public class QueryController
{
private enum QueryType
{
TypeA = 0,
TypeB = 1,
TypeC = 2
}
[HttpGet]
public void ShowResults(QueryType type, string criteria)
{
/*
* Code here to make the query using the field you want,
* depending on the "type" parameter e.g.
*
* switch (type)
* {
* case TypeA:
* model = db.Items.Where(x => x.FieldA == criteria);
* break;
* case TypeB:
* model = db.Items.Where(x => x.FieldB == criteria);
* break;
* }
*/
return View(model);
}
}
Another thing, don't worry about the routes, the default route {controller}/{method}/{id} doesn't demand that you have to specify the URLs in that strict way. This is a valid URL for the previous example:
http://www.example.com/App/Query/ShowResults?type=1&criteria=foo
The default MVC binder will use the parameter names in the URL to bind their values to the parameters of your method.
I hope I didn't misunderstood your question.
Good luck!
With MVC, query string values map to parameter values (and Routes are used to create custom mappings).
There are special exceptions though. If a parameter is a FormCollection (which is basically just a Dictionary<string>), then all un-mapped query string values will be passed in.
So, you can create a single Action that takes in all parameters:
// GET: MyController/ViewList?name=aaa&field1=foo&field2=bar
public ActionResult ViewList(string name, FormCollection otherFields) {
foreach (var field in otherFields) {
switch (field.Key.ToLower()) {
case "field1":
// Filter field1 based on field.Value
case "field2":
// Filter field2 based on field.Value
...
}
}
...
}
Similarly, you could also have no parameters, and just use this.Request.QueryString to inspect the query string values. However, I prefer the FormCollection method because it makes it clear that I expect other parameters.