Maybe no need to tell you, that I have been Googling, looking at the docs & specs, and testing around for couple of days now with no success.
What I'm trying to achieve: I want to bind the rows of my table not to a concrete entity (called Contragent in my case) of the model, but to a service method within the same model, which accepts a parameter, filters the Contragents and returns an IQueryable. I remember yesterday reading in a stackoverflow question - somebody was asking is it possible to implement an sql 'in' clause using only OData url parameters. They had replied, that the only way is to build a string of the form $filter=(Name eq 'test1' and Name eq 'test2' and ...)
. So I thought it would be nice if I could add a custom method to my OData service, where I can comfortably use LINQ in C#. I saw in the OData docs, that it is possible to ask not for an entity of the model, but to query the data from such a method again just writing the proper URL. So basically, this is what I want - to bind my SAP table to select * from Contragent where Name in (select Name from ...)
using the OData service I have created.
What I've done so far: First of all, I learned how to add a custom service method to the OData service. It looks like it has to be placed in the same class where you initialize the service:
public class MyService : EntityFrameworkDataService<MyEntities>
{
// This method is called only once to initialize service-wide policies.
public static void InitializeService(DataServiceConfiguration config) {
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead | EntitySetRights.AllWrite);
//https://debugmode.net/2012/01/13/how-to-work-with-custom-method-in-wcf-data-service/
config.SetServiceOperationAccessRule("*", ServiceOperationRights.All); // for the custom method to be accessible via the service
config.UseVerboseErrors = true;
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
private MyEntities entities = new MyEntities();
//https://docs.microsoft.com/en-us/dotnet/framework/data/wcf/service-operations-wcf-data-services
[WebGet] // this attribute is required - ^see the link above^
public IQueryable<Contragent> GetContragentsByIsContained(int isContained)
{
IQueryable<Contragent> result = entities.Contragent;
List<string> neededNames = GetNeededNames();
if (isContained == 0)
{
result = result.Where(x => !neededNames.Contains(x.Name));
}
else if (isContained == 1)
{
result = result.Where(x => neededNames.Contains(x.Name));
}
// else - no filtering
return result;
}
}
After that, I did some testing and I see, that both URLs http://localhost:port/Services/MyService.svc/GetContragentsByIsContained?isContained=1
and http://localhost:port/Services/MyService.svc/GetContragentsByIsContained?isContained=0
work well.
After that, I tried to
.bindRows({
path: '/GetContragentsByIsContained?isContained=' + (typeof (isContained) === 'string' && isContained !== '' ? isContained: 2));
//...
});
of my table to this result and it does not work.
Opening up Fiddler to see what's going on told me what's the problem. I see, that SAP UI 5 sends the following requests: 400 HTTP localhost:port/Services/MyService.svc/GetContragentsByIsContained
and 400 HTTP localhost:port/Services/MyService.svc/GetContragentsByIsContained?$skip=0&$top=25
. I am not surprised at all, that the server 400's to them, because... hey, SAP, where is the isContained parameter gone!?
This made me do another test in Fiddler or the browser - doesn't matter: http://localhost:port/Services/MyService.svc/GetContragentsByIsContained?isContained=1&$filter=(Name eq 'Test123')
. There is a Contragent named Test123, which is among the desired names, so this query with isContained=1 returns 1 item as it should, while the one with isContained=0 returns no items - again as expected. So it shouldn't be a problem for UI5 library to append the special parameters beginning with $
to the end of my URL with no need to remove my parameter isContained.
So, finally, the question itself: Is it normal for the SAP library to remove everything after ?
in the binding path before loading the data? How can I preserve this parameter? Thanks in advance!
edit: I forgot to tell you, that I tried to add
urlParameters: {
"isContained": (typeof (isContained) === 'string' && isContained !== '' ? isContained : 2 )
}
just like I would do if I wanted to make a read():
model.read("/GetContragentsByIsContained" {
urlParameters: {
"isContained": (typeof (isContained) === 'string' && isContained !== '' ? isContained : 2 )
},
success: function (count, args) {
debugger;
table.rows = count.results; // this doesn't work as well
},
error: function (args) {
debugger;
console.log(args);
}
});
It doesn't work.