Type of Iqueryable at runtime - asp.net-mvc

I have a method which returns Iqueryable result, but the result is based on an if else condition, where if condition satisfies then I will use "AssetDetails" class object ,otherwise "UserandClientdetails" object.
Here is the code:
private IQueryable<?> GetAssetDetails(ShareViewModel item)
{
...
if (type == "Video")
{
if (type == "Video")
{
return from meta in my.Assets().OfType<Model.Video>()
join content in my.Contents() on meta.ContentId equals content.ID
join channel in my.Channels() on content.ChannelId equals channel.ID
where meta.ID == item.ID
select new AssetDetails
{
ContentTitle = content.Title,
ChannelName = channel.ChannelName,
...
};
}
else
{ return from meta in my.Assets().OfType<Model.Client>()
join country in db.Countries on meta.ResellerCountry equals country.ID
where meta.ID == item.ID
select new UserAndClientDetails
{
Name = meta.ResellerName,
UserName = meta.ResellerEmail,
..
};}
So how to decide type of Iqueyable here at runtime??

So, I was able to verify that this works, so I'll go ahead and post it as an answer.
You can return IQueryable instead of the generic IQueryable<>. That will accept any IQueryable<T>. However, IQueryable, since it has no direct inner type, is very limited. So, you'll still likely need to cast to IQueryable<> at some other point in your code to get anything done:
// Piece of code where you know you are working with `IQueryable<AssetDetails>`
IQueryable<AssetDetails> assetDetails = GetAssetDetails(someItem);
That's a little dangerous, though, as you're assuming that your code is working perfectly and the right type of thing is being returned. Better would be:
try
{
var assetDetails = (IQueryable<AssetDetails>)GetAssetDetails(someItem);
// do something with `assetDetails`
}
catch (InvalidCastException)
{
// recover gracefully
}

What about using a base class ?
public abstract class BaseDetails
{
// ...
}
public class AssetDetails : BaseDetails
{
// ...
}
public class UserAndClientDetails: BaseDetails
{
// ...
}
Then you method would be like :
private IQueryable<BaseDetails> GetAssetDetails(ShareViewModel item)
{
// return either IQueryable<AssetDetails> or IQueryable<UserAndClientDetails>
}

Related

Passing a Closure as a method argument in Groovy

I'm writing a service in Grails 3.
Let's say I wrote a method like this for a 'PostsService'
By default it should sort the categories by their id.
List<Category> getCategories(List<Post> posts) {
List<Category> categories = ... // logic to get categories
categories.sort { it.id }
return categories
}
What if I wanted to add flexibility for sorting. For example, later we want to sort by year instead.
I want to add the sort Closure as an optional argument.
I tried this.
List<Category> getCategories(List<Post> posts, Closure sortClosure = null) {
List<Category> categories = ... // logic to get categories
if (sortClosure == null) {
categories.sort { it.id }
} else {
// Trying to use the sortClosure. Not sure if these will work.
// sortClosure << categories.sort
// categories.sort sortClosure
}
return categories
}
I try to run the method with the Closure
List<Category> categories = postsService.getCategories(posts, { it.year })
But I'm running into errors. It throws an internal server error at this line.
List<Category> categories = postsService.getCategories(posts, { it.year })
Class java.lang.NoSuchMethodError
Message null
Caused by PostsController$_select_closure5: method (Ljava/lang/Object;Ljava/lang/Object;)V not found
What am I doing wrong here? Can I use a Closure this way?
One of the resources I've been looking at

Trimming String request parameters in controllers actions

I am working in a grails 2.4.4 application which has some legacy code that doesn't use binding or command objects in controllers, in this application the request parameters are passed from controller actions directly to java classes using their constructors.
We want to trim white spaces from strings parameters (just like Grails does by default when binding) but without using binding or command objects.
Maybe injecting a cloned version of the params varible but with trimmed values?
Have any of you done something like this?
Here's an implementation I used in a 2.x app in a filter. It supports nested objects by calling the method recursively:
def filters = {
blankToNullAndTrim(controller: '*', action: '*') {
before = {
convertBlanksToNullsAndTrim params
true
}
}
}
private static void convertBlanksToNullsAndTrim(Map<String, Object> map) {
def keys = map.keySet() as List // copy to avoid ConcurrentModificationException
for (name in keys) {
def value = map[name]
if (value instanceof String) {
value = value.trim()
if (value.length() == 0) {
map[name] = null // have to explicity set to null, not remove
}
else {
map[name] = value // update if trimmed
}
}
else if (value instanceof Map) {
// empty nested param, e.g. "location":["id":""]
convertBlanksToNullsAndTrim value
}
}
}
and here's the equivalent implementation (with type information included so you can use #GrailsCompileStatic) for use in an interceptor when you upgrade to Grails 3.x:
boolean before() {
convertBlanksToNullsAndTrim params
true
}
private void convertBlanksToNullsAndTrim(Map<String, Object> map) {
List<String> keys = map.keySet() as List // copy to avoid ConcurrentModificationException
for (String name in keys) {
def value = map[name]
if (value instanceof String) {
value = value.trim()
if (value.length() == 0) {
map[name] = null // have to explicity set to null, not remove
}
else {
map[name] = value // update if trimmed
}
}
else if (value instanceof Map) {
// empty nested param, e.g. "location":["id":""]
convertBlanksToNullsAndTrim value
}
}
}
One option will be to use Dynamically Resolved Variables in UrlMappings.groovy. For example if there is a mapping as follows:
"/airport/status(controller: 'airport', action: 'checkStatus')
and expecting a request parameter as airportName then it can be rewritten as:
"/airport/status(controller: 'airport', action: 'checkStatus') {
airportName = { params.airportName?.trim() }
}
This would make sure that the arbitrary variable is set to params after trimming the actual request parameter airportName. Care has to be taken to use the same variable name as the request parameter to support the legacy system underneath.
Another option can be to use a filter across the controller to trim the request parameters. Something like:
class UtilityFilters {
def filters = {
trim(controller: "airport", action: "*") {
before = {
// If immutable then make a copy and edit
params.airportName = params.airportName?.trim()
return true
}
}
}
}

How to map Grails domain class properties to non-matching json string?

Is there a built-in / easy way to set mappings between domain class properties and JSON strings that don't have exact matches for the property names?
For example, when I have a domain class:
class Person {
String jobTitle
String favoriteColor
static constraints = {
jobTitle(blank: false)
favoriteColor(blank: false)
}
}
And someone's giving me the following JSON:
{ "currentJob" : "secret agent", "the-color" : "red" }
I'd like to be able to still do this:
new Person(request.JSON).save()
Is there a way in groovy/grails for me to map currentJob -> jobTitle and the-color -> favorite color?
EDIT:
I've done a little experimenting, but I still haven't gotten it working. But I have found out a couple interesting things...
At first I tried overwriting the setProperty method:
#Override
setProperty(String name, Object value) {
if(this.hasProperty(name)) this[name] = value
else {
switch(name) {
'currentJob': this.jobTitle = value; break;
'the-color': this.favoriteColor = value; break;
}
}
}
But this doesn't work for two reasons: 1) setProperty is only called if there is a property that matches name and 2) "this[name] = value" calls setProperty, leading to an infinite recursive loop.
So then I thought, well screw it, I know what the incoming json string looks like (If only I could control it), I'll just get rid of the line that handles the scenario where the names match and I'll override hasProperty, maybe that will work:
#Override
void setProperty(String name, Object value) {
switch(name) {
'currentJob': this.jobTitle = value; break;
'the-color': this.favoriteColor = value; break;
}
}
#Override
boolean hasProperty(String name) {
if(name == "currentJob" || name == "the-color") return true
return false
}
But no, that didn't work either. By a random stroke of luck I discovered, that not only did I have to overwrite hasProperty(), but I also had to have an empty setter for the property.
void setCurrentJob(){ }
That hack worked for currentJob - I guess setProperty only gets called if hasProperty returns true and there is a setter for the property (Even if that setter is auto generated under the covers in grails). Unfortunately I can't make a function "setThe-Color" because of the dash, so this solution doesn't work for me.
Still stuck on this, any help would definitely be appreciated.
EDIT:
Overriding the void propertyMissing(String name, Object value){} method is called by this:
Person person = new Person()
person["currentJob"] = "programmer"
person["the-color"] = "red"
But not by this:
Person person = new Person(["currentJob":"programmer", "the-color":"red"])

Search and get all parents that contains a child with value

class Client {
String name
static hasMany = [courses:Course]
}
class Course {
String name
static belongsTo = [client:Client]
}
I have this and I want to get all Clients that has a Course with name = "blabla"
I was trying to do : Clients.findWhere(Course.any { course -> course.name = "math" })
You can do this with criteria:
Client.withCriteria {
courses {
eq('name', 'math')
}
}
I believe that the following where query is equivalent to the above criteria:
Client.where { courses.name == 'math' }
or you may find you need another closure:
Client.where {
courses {
name == 'math'
}
}
but I rarely use where queries myself so I'm not 100% sure of that.
There are probably a lot of different syntactical expressions to achieve the same thing. I can say definitively that this works in my project though.
def ls = Client.list {
courses {
eq('name','math')
}
}

OntModel interface has no listHierarchyRootProperties method

Jena's OntModel has a method listHierarchyRootClasses that returns an iterator over the classes in this ontology model that represent the uppermost nodes of the class hierarchy. But why does OntModel have no method of the same function for the semantic properties? There is a property hierarchy as well, so why developers make a listHierarchyRootProperties?
I have solved this by using listAllOntProperties method, but it is a workaround, and does not look good. I don't understand why is it necessary. What is the reason?
Jena is an open-source project. You are more than welcome to submit a patch with the additional functionality you would like to see in the library. Please submit patches via the Jira account.
To answer your direct question: there's no particular reason why there's no equivalent for the property hierarchy. However, property inheritance isn't as widely used as as class inheritance in OWL, and in all the years since I wrote listHierarchyRootClasses, you're the first person I can remember asking about the property hierarchy.
Here is my workaround, which produces alphabetically sorted hierarchy (tree) of semantic properties. The getPropertyTreeModel() method returns a model for an ice:tree component and the parameter domContent is not important (it is for my special needs):
protected static DefaultTreeModel getPropertyTreeModel(OntModel ontModel, Document domContent) {
System.out.println("Creating property model...");
DefaultMutableTreeNode rootTreeNode = getRoot();
DefaultTreeModel treeModel = new DefaultTreeModel(rootTreeNode);
Iterator i = getAlphabeticalIterator(ontModel.listAllOntProperties().filterDrop(new Filter() {
#Override
public boolean accept(Object o) {
return !((OntProperty) o).listSuperProperties(true).toList().isEmpty();
}
}));
while (i.hasNext()) {
joinResource(rootTreeNode, (OntProperty) i.next(), new ArrayList(), OntProperty.class, domContent);
}
return treeModel;
}
private static Iterator getAlphabeticalIterator(ExtendedIterator ei) {
List l = ei.toList();
Collections.sort(l, new Comparator<OntResource>() {
#Override
public int compare(OntResource o1, OntResource o2) {
return (o1.getLocalName().compareTo(o2.getLocalName()));
}
});
return l.iterator();
}
private static DefaultMutableTreeNode getRoot() {
DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode();
ClassNodeUserObject rootObject = new ClassNodeUserObject(rootTreeNode);
rootObject.setExpanded(true);
rootTreeNode.setUserObject(rootObject);
return rootTreeNode;
}
private static void joinResource(DefaultMutableTreeNode parent, OntResource res, List occurs, Class c, Document domContent) {
DefaultMutableTreeNode branchNode = new DefaultMutableTreeNode();
SemanticNodeUserObject branchObject = (c.equals(OntClass.class))
? new ClassNodeUserObject(branchNode) : new PropertyNodeUserObject(branchNode);
branchObject.setOntResource(res);
branchObject.setExpanded(false);
branchObject.setLeaf(true);
// optimalizace: v pripade prazdneho souboru bez parsovani, aktualizace barev
if (domContent != null) {
setColorToNode(branchObject, domContent);
}
branchNode.setUserObject(branchObject);
parent.add(branchNode);
// rekurze
if (res.canAs(c) && !occurs.contains(res)) {
ExtendedIterator ei = (c.equals(OntClass.class)) ? ((OntClass) res).listSubClasses(true)
: ((OntProperty) res).listSubProperties(true);
branchObject.setLeaf(!ei.hasNext());
for (Iterator i = getAlphabeticalIterator(ei); i.hasNext();) {
OntResource sub = (OntResource) i.next();
occurs.add(res);
joinResource(branchNode, sub, occurs, c, domContent);
occurs.remove(res);
}
}
}

Resources