I can submit a support ticket if that's a preferred way.
Thanks
21 Answers, 1 is accepted
The FilterDescriptor is a public class which is available in the Kendo.Mvc namespace. It is basically the same as in Telerik Extensions for ASP.NET MVC. I have attached this file for your convenience.
On a side note the source code will be available with the official release.
Atanas Korchev
the Telerik team
We had a similair question before - may I suggest that you expose the internal sorting and filtering function as public? That is - to use it the filtering and sortering right now we concluder (correctly?) that you have to call ToDataSourceResult() and use the result. It would however be nice if the sort/filter/etc functionality is exposed as well.
Otherwise, very clean solution (returing Json(....ToDataSourceRequest()) etc) compared to the [GridAttribute] solution in Telrik ASP MVC. Very nice and transparent!
Thanks!
/Victor
Those are already exposed as IQyeryable extension methods: Page, Sort, GroupBy etc.
All the best,Atanas Korchev
the Telerik team
We know that those functions are exposed, however it would be nice if the function calling all the separate functions (sort, filter, etc) was exposed as well. Preferably taking in IQueryable<T> and returning IQuearyable<T> if possible.
Edit: Since we feel we might miss something if we use the individual functions we right now use the ToDataSourceResult() with some casting to get it back to the original type. We do this in the server side function generating the grid to get the same behaviour as for the functions returning the Json results for paging/sorting/etc.
/Victor
We don't have such a function because we need the Total count of records as well. It would be lost if we process all data in a single method.
All the best,Atanas Korchev
the Telerik team
We realize that, and we realize that it would not (and should not) replace the ToDataSourceResult() function, it would still be convenient to have the sort/filter/etc functionality exposed in a single function. We could then do something like:
var viewModel =
new
CustomViewModel();
var unfilteredList = GetCustomViewModelList();
viewModel.TotalRows = unfilteredList.Count();
viewModel.Records = unfiltereredList.ApplyRequestFiltering(request);
return
View(viewModel);
and refactor most of this code to be common between server side and ajax request functions. One reason we want this is since we often have som post-processing that shoud be done after sorting and filtering has been done to add some custom, complex properties in memory, similair to:
var viewModel =
new
CustomViewModel();
var unfilteredList = GetCustomViewModelList();
viewModel.TotalRows = unfilteredList.Count();
viewModel.Records = unfiltereredList.ApplyRequestFiltering(request).ToList();
//actual EF query to result in memory
viewModel.Records.ForEach(record => record.CustomProperty = String.Join(
","
, record.CustomListProperty));
return
View(viewModel);
Right now this is possible via Cast<CustomViewModel> after calling ToDataSourceResult(), unfortunately this creates quite cumbersome code. So optimally we would like the option to do something like:
//Code as before but refactored
return
View(alreadyFilteredAndSortedViewModel.AddCustomCalculatedProperties().ToDataSourceResult(totalCount));
Hope this clarifies our objectives. Of course the implementation could be different, but the goal would for us be:
- Possibility to refactor out creation, filtering and sorting to a method to be used for both server-side and ajax requests
- Possibility to use non-db functions on the resulting, filtered, request (such as String.Join()), thus applied on 20 results rather than on 20000.
I will add this for to our TODO list. Hopefully it would make it in the final release.
Greetings,Atanas Korchev
the Telerik team
/Victor
While researching the implementation of such extension methods I found to obstacles. The ToDataSourceResult extension method supports aggregates and grouping. However the result from those two operations is no longer IQueryable<T>. This means that an extension method which takes IQueryable<T> and returns IQueryable<T> will not support aggregates and grouping. In this case I don't think such a method would have any value.
Right now we can either expose a method called ProcessDataSourceRequest which will not support (and never support) grouping and aggregates or just skip that method altogether. What do you think?
Atanas Korchev
the Telerik team
A more complete example of what we are trying to accomplish can be found in this other thred: http://www.kendoui.com/forums/mvc/grid/grid-reorders-server-side-data-even-when-no-sort-order-is-specified.aspx#2170196
Basically the part feels very cumbersome, but that was the best we could come up with for now:
var result = producers
.Take(request.PageSize)
.ToList()
.ToDataSourceResult(request);
var producersList = result.Data.Cast<
ProducerViewModel
>().ToList();
Hopefully this clarifies some, otherwise, please get back to us!
/Victor
Your code will also fail if grouping or aggregates are enabled. The following cast will fail:
result.Data.Cast<ProducerViewModel
>().ToList();
So the question I am asking is how grouping and aggregates should be handled in this case - an exception should be thrown or what?
Atanas Korchev
the Telerik team
Anyway, as you can see from the linked thread (previous post), we want to be able to post-process the correct page of results in-memory.
So - I suppose what we need to do is (have I missed any steps?):
- Sort
- Skip
- Take
- ToList (DB => Memory)
- Custom post processing (processing that cannot be done on the DB side)
- ToDataSourceResult
Also in (6) we would need to provide some inputs from (1)-(3), such as total count and current page number.
/Victor
This seems about right. You can reset the paging and sorting info to avoid double paging and sorting:
request.Page = 0;
request.PageSize = 0;
result = data.Skip().Take().OrderBy().ToList().ToDataSourceResult(request);
Regards,
the Telerik team
Thanks for that! However I am not sure how to do this correctly currently. 1-5 is not Kendo related and will be done "as usual" (with changes to work with datasourcerequest of course), however 6 I am not sure about...
How do I return a datasource-result correctly? That is - before (1) i take out the full IQueryable the count, I do 1-5. I then have a list of say 25 sorted items (from page 10, out of 1000) and want to return the correct datasourceresponse supporting aggregates and filters.
/Victor
I am starting to think that this problem should be solved in a different manner. If the only thing you want is to do some sort of projection over the process data we can probably think find another solution. How about something like this?
var result = data.ToDataSourceResult(request, (db) => toMemory(db))
The extension method would take the selector and use it internally to do the required projections. Do you think this would work?
Regards,
the Telerik team
Sounds like a very tempting solution! I am not sure exactly how you think about implementing it, but for us we need to be able to provide a custom projection. Usually we use Automapper for our projections and will need for custom aggregate functions not supported in the DB, such as String.Join() in the simplest case. Automapper is of course not a requirement, but the syntax is very appealing:
IEnumerable<OrderViewModel> dto = Mapper.Map<IEnumerable<Order>, IEnumerable<OrderDto>>(ordersFromDb);
If I understand you correctly we would do something like one of these two:
(1)
var db = companiesSet.Where(...);
var result = data.ToDataSourceResult(request, (db) => toMemory(db));
...
function CompanyViewModel toMemory(Company dbCompany) {
return
Mapper.Map<Company, CompanyViewModel>(dbCompany);
//Or non Automapper projection
}
(2)
var db = companiesSet.Where(...).Select(c =>
new
CompanyViewModel(...));
var result = data.ToDataSourceResult(request, (db) => inMemoryPostProcessing(db));
...
function CompanyViewModel inMemoryPostProcessing(CompanyViewModel companyViewModel) {
//Custom in memory code such as sting join
}
Is that what you suggest?
/Victor
Yes, #1 is the way I was thinking it could work. The implementation won't be easy but is still doable and would work in all cases (even when grouping and aggregates are involved).
Regards,Atanas Korchev
the Telerik team
/Victor
I've just implemented that overload. The feature would be available in the official release.
All the best,Atanas Korchev
the Telerik team
/Victor
My code:
DataSourceResult result = this.StateProvinceService
.GetQueryable()
.ToDataSourceResult<StateProvince, StateProvinceModel>(
request,
province => Mapper.Map<StateProvince, StateProvinceModel>(province));
The result:
LINQ to Entities does not recognize the method 'XYZ.Web.Areas.Admin.Models.StateProvinceModel Map[StateProvince,StateProvinceModel](XYZ.Model.StateProvince)' method, and this method cannot be translated into a store expression.
Any advice?