I want to implement server side paging/sorting/etc using [DataSourceRequest] DataSourceRequest request
and ToDataSourceResult
I've done this hundreds of times using LINQ and EF, however, this current project requires us to utilized stored procedures, called by context.Database.SqlQuery
This works fine, except in the case where I need to pass parameters into the stored procedure as well, which results in the error:
The SqlParameter is already contained by another SqlParameterCollection.
I assume the reason for this is that Kendo's ToDataSourceResult
is also trying to attach SQL parameters to the data
object, which C# doesn't like.
Some solutions I saw online were to call .ToList()
, which does work, however, it sort of defeats to purpose, as it will still query all results.
var data = context.Database.SqlQuery<TicketVm>("usp_FleetRentedEquipments @analyst",
new SqlParameter("@analyst", analyst));
return data.ToDataSourceResult(request);
Inside the ToDataSourceResult method, the query is used at least twice - once in a call to Count() and once to pull the data. This causes the error for using the SQL Parameter set twice. You can likely only do this:
var data = context.Database.SqlQuery<TicketVm>($"usp_FleetRentedEquipments {analyst}");
return data.ToDataSourceResult(request);
And be very careful 'analyst' is not an SQL injection.
I've just done it like this (note: I'm using Dapper and EF)
var gridBinder = new GridBinder(request);
var filters = gridBinder.GetFilterDescriptor();
var sorting = gridBinder.SortInfo.Member.HasValue() ? string.Format("{0} {1}", gridBinder.SortInfo.Member, gridBinder.SortInfo.Direction) : "";
var p = new DynamicParameters();
p.Add("@Page", gridBinder.PageNumber, DbType.Int32, ParameterDirection.Input);
p.Add("@PageSize", gridBinder.PageSize, DbType.Int32, ParameterDirection.Input);
p.Add("@Filter", filters);
p.Add("@SortOrder", sorting);
p.Add("@TotalRowCount", dbType: DbType.Int32, direction: ParameterDirection.Output);
var data = _db.Connection().Query<IndexVm>("dbo.People_GetAll", p, commandType: System.Data.CommandType.StoredProcedure, transaction: _db.Database.CurrentTransaction.GetDbTransaction());
gridBinder.RecordCount = data.FirstOrDefault().TotalRowCount;
return Json(new DataSourceResult
{
Total = gridBinder.RecordCount,
Data = data
});
GridBinder
public class GridBinder
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public int RecordCount { get; set; }
public SortInfo SortInfo { get; set; } = new SortInfo() { Direction = SortDirection.Asc, Member = string.Empty };
private readonly DataSourceRequest _command;
public GridBinder(DataSourceRequest command)
{
_command = command;
PageNumber = command.Page;
PageSize = command.PageSize;
GetSortDescriptor();
}
private void GetSortDescriptor()
{
foreach (SortDescriptor descriptor in _command.Sorts)
{
SortInfo.Member = descriptor.Member;
SortInfo.Direction = descriptor.SortDirection == ListSortDirection.Ascending ? SortDirection.Asc : SortDirection.Desc;
}
}
public string GetFilterDescriptor()
{
string filters = string.Empty;
foreach (IFilterDescriptor filter in _command.Filters)
{
filters += ApplyFilter(filter);
}
return filters;
}
private static string ApplyFilter(IFilterDescriptor filter)
{
var filters = "";
if (filter is CompositeFilterDescriptor)
{
filters += "(";
var compositeFilterDescriptor = (CompositeFilterDescriptor)filter;
foreach (IFilterDescriptor childFilter in compositeFilterDescriptor.FilterDescriptors)
{
filters += ApplyFilter(childFilter);
filters += " " + compositeFilterDescriptor.LogicalOperator.ToString() + " ";
}
}
else
{
string filterDescriptor = "{0} {1} {2}";
var descriptor = (FilterDescriptor)filter;
if (descriptor.Operator == FilterOperator.StartsWith)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "LIKE", "'" + descriptor.Value + "%'");
}
else if (descriptor.Operator == FilterOperator.EndsWith)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "LIKE", "'%" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.Contains)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "LIKE", "'%" + descriptor.Value + "%'");
}
else if (descriptor.Operator == FilterOperator.DoesNotContain)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "NOT LIKE", "'%" + descriptor.Value + "%'");
}
else if (descriptor.Operator == FilterOperator.IsEqualTo)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "=", "'" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.IsNotEqualTo)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "<>", "'" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.IsGreaterThan)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, ">", "'" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.IsGreaterThanOrEqualTo)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, ">=", "'" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.IsLessThan)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "<", "'" + descriptor.Value + "'");
}
else if (descriptor.Operator == FilterOperator.IsLessThanOrEqualTo)
{
filterDescriptor = string.Format(filterDescriptor, descriptor.Member, "<=", "'" + descriptor.Value + "'");
}
filters = filterDescriptor;
}
filters = filters.EndsWith("And ") == true ? filters.Substring(0, filters.Length - 4) + ")" : filters;
filters = filters.EndsWith("Or ") == true ? filters.Substring(0, filters.Length - 4) + ")" : filters;
return filters;
}
}
public class SortInfo
{
public string Member { get; set; }
public SortDirection Direction { get; set; }
}
public enum SortDirection
{
Asc, Desc
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With