Odata $top doesn't work with MongoDb - odata

I've stuck into some weird problem. Here is the code
AccountsController.cs
// GET /api/accounts
[HttpGet]
[Queryable(ResultLimit = 50)]
public IQueryable<AccountDto> Get()
{
return this.service.Get();
}
service here - it's AccountService.cs
public IQueryable<AccountDto> Get()
{
return this.readModel.Get();
}
and readModel is of type AccountsReadModel
public IQueryable<AccountDto> Get()
{
return Database.GetCollection<AccountDto>("Accounts").AsQueryable();
}
Database is MongoDb.Driver.Database
the problem is following:
when I trying to query Get method without any parameters -
localhost/api/accounts - it returns all accounts (as intended)
when I use skip: localhost/api/accounts?$skip=n - it skips n and returns rest items
(as intended too)
but, localhost/api/accounts?$top=1 returns all accounts, instead of one.
How can I handle it?

The problem was in [Queryable(ResultLimit=50)]:
it and $top=1 together produces following expression:
coll.Take(1).Take(50) which returns not 1, but 50 (or all elements in collection, in case if there are less elements than 50).
By the way, Database.GetCollection<A>("A").AsQueryable().Take(1).Take(50) - returns not 1 element again.
This looks like bug in MongoDbDriver

use with $orderby
localhost/api/accounts?$top=1&$orderby=...

Related

Mapping lack of understanding

I read a lot about this topic and I understand it quit good.
But, the only thing I don't understand is how in functions developers use it without a function that insert the values.
example:
mapping (uint256=>address) public IdToAddress;
after they defines it I see that they are using in functions like:
function HolderOfNFT(Uint256 Id) public returns (address) {
return IdToAddress[Id];
}
How the mapping has value in the Id key that points to the right address?
Thanks a lot!!
All mapping values are empty by default.
So unless the value is set somewhere in the code, your example would return address(0) for any Id.
You can assign a mapping value the same way as you'd assign it to an array. Examples:
IdToAddress[Id] = address(0x123);
function transfer(address _recipient, uint256 _id) public {
require(IdToAddress[_id] == msg.sender, "You're not the current token owner");
IdToAddress[_id] = _recipient;
}

Unable to make simple Apex class invocable - find custom location record based on coordinate input

I've got a simple class containing a SOQL query that finds the nearest custom location record based on the input of 2 coordinates:
public with sharing class NearestLocation {
#InvocableMethod(label='Get Nearest location' description='From given coordinates the nearest location is returned')
public static List<custom__Location__c> getLocation(List<FlowInput> requests)
{
List<custom__Location__c> locList =
[SELECT id, Name
FROM custom__Location__c WHERE RecordType.Name = 'Synced' AND
DISTANCE(custom__GeoLocation__c, GEOLOCATION(:requests[0].coordlat, :requests[0].coordlng), 'km')<1
ORDER BY DISTANCE(custom__GeoLocation__c, GEOLOCATION(:requests[0].coordlat, :requests[0].coordlng), 'km')
LIMIT 1];
for(custom__Location__c lc : locList)
{
system.debug('~~!~~!~~' + lc.id);
system.debug('~~!~~!~~' + lc.name);
}
return locList;
}
public class FlowInput
{
#InvocableVariable(required=true)
public decimal coordlat;
#InvocableVariable(required=true)
public decimal coordlng;
} }
The above code works as expected when run from Execute Anon:
list <NearestLocation.FlowInput> fi = new list<NearestLocation.FlowInput>();
NearestLocation.FlowInput x1 = new NearestLocation.FlowInput();
x1.coordlat = 53.243213;
x1.coordlng = -1.475886;
fi.add(x1);
NearestLocation.getLocation(fi);
However, I'm trying to get it to be 'invoked' from within a lightning flow, but it fails with a generic 'flow has validation errors'​ message.
lightning flow - apex action
execution log - flow has validation errors
I'm obviously missing something and was wondering if anyone could offer some guidance/thoughts?
try to return List> if you assign the output to a collection variable.
RESOLVED. 
Nothing inheritently wrong with the code....problems were due to unrelated formula in the lightning flow!  Hmmm...note to self...start with a blank canvas!
Thanks for the response Ahmed. It is returning a list:
public static List
return locList;

custom OData v4 function always returns 406

So I'm trying to map this method as an Odata function ...
[HttpGet]
[EnableQuery]
public IHttpActionResult ForBuyerOrganisations([FromUri]int[] orgIds)
{
// this returns IQueryable<TRDetails>
// i tried throwing a ToList on there too to ensure it works and it does
var result = service.ForBuyerOrgs(orgIds);
return Ok(result);
}
I have mapped it like this ...
var forBuyers = Builder.EntityType<TRDetails>().Collection.Function("ForBuyerOrganisations");
forBuyers.ReturnsCollection<TRDetails>();
forBuyers.CollectionParameter<int>("orgIds");
... I also tried this ...
var forBuyers = Builder.EntityType<TRDetails>().Collection.Function("ForBuyerOrganisations");
forBuyers.ReturnsCollectionFromEntitySet<TRDetails>();
forBuyers.CollectionParameter<int>("orgIds");
I can call it with the url:
~/TRDetails/ForBuyerOrganisations?orgIds=1
The Problem:
The request executes my code and returns from this method, then the client gets a 406.
Any Ideas?
Yes. #Ouyang indicates the config error. Besides, as I seem, there are other four errors:
you should use [FromODataUri], not [FromUri] for the parameter.
you should call the function with namespace-qualified.
TRDetails/Namespace.ForBuyerOrganisations(...)
you should set the argument as list, because you config it as collection.
you should call the function using the () for parameter.
So, the following request is sample request:
~/TRDetails/Default.ForBuyerOrganisations(orgIds=[5,4,2,3,1])
If TRDetails is an entityset,
forBuyers.ReturnsCollectionFromEntitySet<TRDetails>("TRDetails");
I think you miss the entityset's name.

ASP.NET MVC - Proper way to handle ajax actions with no return object

I have a controller action that does some work in the database and then exits when it's finished. This action is being called via jQuery's ajax function with the dataType set to 'json'.
If I set the return type of the action to void, everything will function just fine except Firefox will show an error in the console that says: "no element found".
It makes sense that Firefox would throw this error if it was expecting XML to come back. However, even when I change the dataType property of the ajax call to "text", I still receive the error. In order to get rid of the error with the return type void, I would have to set the Response's ContentType to "text/html". Or I could set the return type to JsonResult and return a new [empty] JsonResult object.
I'm sure there are several ways I can make this error go away, but I wanted to know the proper way to handle actions with no return values being called via ajax.
If it matters, I'm also using the async controller action pattern.
public void DoSomethingAsync(SomeJsonObjectForModelBinding model)
{
// do some database things
}
public void DoSomethingCompleted()
{
// nothing to do...
// what should my return type be?
// do I need to set the content type here?
}
I know this doesn't exactly answer your question, but I would argue that you should always have a return value coming back from an AJAX or web service call. Even if only to tell you that the operation was successful, or otherwise return the error (message) back to you.
I often define a class like this:
public class JsonResultData
{
private bool _success = true;
public bool Success
{
get { return _success; }
set { _success = value; }
}
public object Value { get; set; }
public List<string> Errors { get; set; }
public JsonResultData()
{
this.Errors = new List<string>();
}
}
And then use it to return data or any other call meta data in the JsonResultData wrapper like so:
return new JsonResult {
Data = new JsonResultData { Value = returnValue, Success = true }
};
I can't comment because of my reputation but I still wanted to contribute to clear the confusion in Kon's answer.
In an application I caught all exceptions within an ActionMethod, set an HttpStatusCode and added an error message to the response. I extracted the message in the Ajax error function and showed it to the user.
Everything worked out fine until the application got put on the staging server, who had some kind of settings that did not allow a return message within an erroneous response. Instead some standard Html was transmitted resulting in a JS error processing the response.
In the end I had to rewrite all my exception handling returning my application errors as successful Ajax call (which it actually is) and then differ within the Ajax success function, just the way it should be.
You should not mix system-level and application-level feedback. You may not be able to control the system-level feedback the way your application needs.

Method not called when using yield return

I'm having a little trouble with a method in which I use yield return this doesn't work...
public IEnumerable<MyClass> SomeMethod(int aParam)
{
foreach(DataRow row in GetClassesFromDB(aParam).Rows)
{
yield return new MyClass((int)row["Id"], (string)row["SomeString"]);
}
}
The above code never runs, when the call is made to this method it just steps over it.
However if I change to...
public IEnumerable<MyClass> SomeMethod(int aParam)
{
IList<MyClass> classes = new List<MyClass>();
foreach(DataRow row in GetClassesFromDB(aParam).Rows)
{
classes.Add(new MyClass((int)rows["Id"], (string)row["SomeString"]);
}
return classes;
}
It works just fine.
I don't understand why the first method never runs, could you help me in understanding what is happening here?
The "yield" version is only "run" when the caller actually starts to enumerate the returned collection.
If, for instance, you only get the collection:
var results = SomeObject.SomeMethod (5);
and don't do anything with it, the SomeMethod will not execute.
Only when you start enumerating the results collection, it will hit.
foreach (MyClass c in results)
{
/* Now it strikes */
}
yield return methods are actually converted into state machine classes that retrieve information lazily - only when you actually ask for it. That means that in order to actually pull data, you have to iterate over the result of your method.
// Gives you an iterator object that hasn't done anything yet
IEnumerable<MyClass> list = SomeMethod();
// Enumerate over the object
foreach (var item in list ) {
// Only here will the data be retrieved.
// The method will stop on yield return every time the foreach loops.
}
The reason it runs in the second case is because there's no yield block, and thus the entire method runs in one go.
In this specific case, it's unlikely that you'll have any advantage to use an iterator block over a regular one because your GetClassesFromDb() isn't one either. This means that it will retrieve all the data at the same time first time it runs. Iterator blocks are best used when you can access items one at a time, because that way you can stop if you don't need them anymore.
I had to learn in a near disastrous way how cool/dangerous yield is when I decided to make our company's parser read incoming data lazily. Fortunately only one of the handful of our implementing functions actually used the yield keyword. Took a few days to realize it was quietly not doing any work at all.
The yield keyword it will be as lazy as it possibly can, including skipping over the method altogether if you don't put it to work with something like .ToList() or .FirstOrDefault() or .Any()
Below are two variations, one using the keyword and one returning a straight-up list. One won't even bother to execute, while the other will, even though they seem the same.
public class WhatDoesYieldDo
{
public List<string> YieldTestResults;
public List<string> ListTestResults;
[TestMethod]
public void TestMethod1()
{
ListTest();
Assert.IsTrue(ListTestResults.Any());
YieldTest();
Assert.IsTrue(YieldTestResults.Any());
}
public IEnumerable<string> YieldTest()
{
YieldTestResults = new List<string>();
for (var i = 0; i < 10; i++)
{
YieldTestResults.Add(i.ToString(CultureInfo.InvariantCulture));
yield return i.ToString(CultureInfo.InvariantCulture);
}
}
public IEnumerable<string> ListTest()
{
ListTestResults = new List<string>();
for (var i = 0; i < 10; i++)
{
ListTestResults.Add(i.ToString(CultureInfo.InvariantCulture));
}
return ListTestResults;
}
}
Moral of the story: Make sure that if have a method that returns IEnumerable and you use yield in that method, you have something that will iterate over the results, or the method won't execute at all.

Resources