I get this error when I'm doing the datatable serverside processing.
The error is thrown when I call this method with Ajax.
I think the problem is server-side coding and I didn't get the problem maybe it's a dynamic linq syntax error.
What is the right syntax for dynamic linq for this statement?
This is my C# code:
public ActionResult Indexer()
{
int start = Convert.ToInt32(Request["start"]);
int length = Convert.ToInt32(Request["length"]);
string searchValue = Request["search[value]"];
string sortColumnName = Request["columns["+Request["order[0][column]"] + "][name]"];
string sortDirection = Request["order[0][dir]"];
int recordsTotal = 0;
List<Employee> Employee = _context.Employees.ToList();
if (!string.IsNullOrEmpty(searchValue)) //filter
{
Employee = Employee.Where(x => x.Emp_ID.ToString().Contains(searchValue.ToString()) ||
x.First_Name.ToLower().Contains(searchValue.ToLower()) ||
x.Last_Name.ToLower().Contains(searchValue.ToLower()) ||
x.Gender.ToLower().Contains(searchValue.ToLower()) ||
x.Salary.ToString().Contains(searchValue.ToString())).ToList();
}
//sorting
if (!(string.IsNullOrEmpty(sortColumnName) && string.IsNullOrEmpty(sortDirection)))
{
// This line throws the error
Employee = Employee.OrderBy(sortColumnName + " " + sortDirection).ToList();
}
// Paging
Employee = Employee
.Skip(start).Take(length)
.ToList<Employee>();
recordsTotal = Employee.Count();
return Json(new { data = Employee }, JsonRequestBehavior.AllowGet);
}
And this is the script which I believe is fine:
#section scripts {
<script src="https://cdn.datatables.net/1.12.1/js/jquery.dataTables.min.js"></script>
<script>
$(document).ready(function () {
$('#mytable').DataTable({
"ajax": {
"url": "/Home/Indexer",
"type": "POST",
"datatype": "josn",
},
"columns": [
{ "data": "Emp_ID", "name": "Emp_Id" },
{ "data": "First_Name", "name": "First_Name" },
{ "data": "Last_Name", "name": "Last_Name" },
{ "data": "Gender", "name": "Gender" },
{ "data": "Salary", "name": "Salary" },
],
"serverSide": "true",
"order": [0, "acs"],
"processing": "true",
});
})
</script>
}
You have a couple of problems here.
First, the list
List<Employee> Employee = _context.Employees.ToList();
is a really bad idea. It's reading the entire database table into memory, which, if it's large, could cause memory issues. But, more importantly, everything done after that will be done in C# on your web server, instead of by the database server. -- You are cutting the database server out of the very thing it was designed to do.
You want to keep it as an IQueryable<> until the very end, and that would be the only place you use .ToList().
IQueryable<Employee> Employee = _context.Employees;
Next, we have the first if(), which is mostly fine, but you know searchValue is a string, so why are you continually trying to convert it to a string? Why keep converting it to lower case? And again, no ToList()
if (!string.IsNullOrEmpty(searchValue)) //filter
{
searchValue = searchValue.ToLower();
Employee = Employee.Where(x => x.Emp_ID.ToString().Contains(searchValue) ||
x.First_Name.ToLower().Contains(searchValue) ||
x.Last_Name.ToLower().Contains(searchValue) ||
x.Gender.ToLower().Contains(searchValue) ||
x.Salary.ToString().Contains(searchValue));
}
Now, we get to the line you asked about. Basically, you are trying to get LINQ to use SQL syntax. Linq wants its own. But first, you have a logic error in your if() statement. You have essentially if (!(A && B)). That's equal to if(!A || !B). What you really want is if(!A && !B).
if (!string.IsNullOrEmpty(sortColumnName) && !string.IsNullOrEmpty(sortDirection))
{
Getting the proper OrderBy statement from a string is a tricky topic, requiring reflection, nicely documented in this question:
Dynamic Order By in Linq
Finally, we actually run the query of the dataserver, which is triggered by the ToList().
// Paging
var lstEmployee = Employee
.Skip(start).Take(length)
.ToList();
recordsTotal = lstEmployee.Count();
return Json(new { data = lstEmployee }, JsonRequestBehavior.AllowGet);
Related
My root data has several sub collections, and I need to do a where clause on 2 of them, sample:
{
"id": "000092224369_0030",
....
"orderData": {
...
"request_secondary": {
"_type": "request_secondary",
"secondary_requests": [{
"secondary_description":"do something" }]
},
"partnership": {
"contacts": [
{
"role": "AG",
"first_name": "LIEBENS Eric",
"last_name": null,
"_type": "contact",
"email": "eric.liebens#gmail.com",
"tel1": "0495-543905",
"tel2": null,
"vat": null
},
{
"role": "ZO",
"first_name": "Coralie",
"last_name": "Demeyere",
"_type": "contact",
"email": "coralie.demeyere#ores.net",
"tel1": "069/256533",
"tel2": null,
"vat": null
},
{
"role": "ZR",
"first_name": "GASBARRO Gianni",
"last_name": null,
"_type": "contact",
"email": null,
"tel1": "0495-385479-0",
"tel2": null,
"vat": "BE0474281005"
}
],
...
Here I need to do a query that bring back the record where any secondary_description equals a text, or a contact with a name with that text.
It should translate to sql for in something this:
SELECT c.id from c
join x in c.orderData.request_secondary
join y in c.orderData.partnership.contacts
where x.secondary_description ='sometin' or y.first_name= 'sometin'
I have tried this solution:
How to query sub document (list type) in Cosmos Db
It works great with one sub collection, but I have no idea how i could get this to work with several selectmany...
Is there any way I can do this in linq?
Thanks!
Based on your description, i think your SQL needs to be tweaked a little bit.
SELECT c.id from c
join x in c.orderData.request_secondary.secondary_requests
join y in c.orderData.partnership.contacts
where x.secondary_description ='something' or y.first_name= 'something'
However, there's going to be duplicate data in the results.So , I also suggestion you adopt the stored procedure which I answered in the thread:How to query sub document (list type) in Cosmos Db.
function sample() {
var collection = getContext().getCollection();
var isAccepted = collection.queryDocuments(
collection.getSelfLink(),
'SELECT * FROM root r',
function (err, feed, options) {
if (err) throw err;
if (!feed || !feed.length) getContext().getResponse().setBody('no docs found');
else {
var returnResult = [];
for(var i = 0;i<feed.length;i++){
var isContinue = true;
var array1 = feed[i].orderData.request_secondary.secondary_requests;
var array2 = feed[i].orderData.partnership.contacts;
for(var j = 0;i<array1.length;j++){
if(array1[j].secondary_description == 'something'){
returnResult.push(feed[i]);
isContinue=false;
break;
}
}
if(isContinue){
for(var k = 0;i<array2.length;k++){
if(array2[j].first_name == 'something'){
returnResult.push(feed[i]);
break;
}
}
}
}
getContext().getResponse().setBody(returnResult);
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.');
}
Update Answer:
You could build LINQ from SQL follow the doc.
client.CreateDocumentQuery().SelectMany((x) =>
x.orderData.requestSecondary.secondaryRequests.Where(
s=>s.secondaryDescription == "something"
) ||
x.orderData.partnership.contacts.Where(
c=>c.firstName == "something"
)
However , i think you still need to resolve the duplicate data of the result set on your client.
Hope it helps you.
I have been trying to get the title, description, start and end date in the periods array based on the time given, I have the following JSON data (the variable name of the following is _json):
Update:
What I want to do is to get the title, description, start and enddate in the periods json array, the condition of it will be based on the start and enddate in the periods json array.
[
{
"ID": "1",
"Title": "First Title",
"Description": "First Description",
"Periods": [
{
"StartDate": "2017-04-23 15:30",
"EndDate": "2017-04-23 15:40"
},
{
"StartDate": "2017-04-23 15:42",
"EndDate": "2017-04-23 15:45"
},
{
"StartDate": "2017-04-23 15:47",
"EndDate": "2017-04-23 15:50"
}
]
},
{
"ID" : "2",
"Title": "Second Title",
"Description": "Second Description",
"Periods": [
{
"StartDate": "2017-04-23 15:52",
"EndDate": "2017-04-23 15:55"
},
{
"StartDate": "2017-04-23 15:57",
"EndDate": "2017-04-23 16:00"
},
{
"StartDate": "2017-04-23 16:02",
"EndDate": "2017-04-23 16:05"
}
]
}
]
And here is my code:
public sealed class Information
{
public List<Period> Periods;
public string Title;
public string Description;
public int ID;
}
public sealed class Period
{
public DateTime StartDate;
public DateTime EndDate;
}
var informations = JsonConvert.DeserializeObject<List<Information>>(_json);
var information = GetData(informations, DateTime.Now);
private Information GetData(List<Information> informations, DateTime dateToCheck)
{
return informations.Select(x =>
{
x.Periods = x.Periods
.TakeWhile(y => dateToCheck >= y.StartDate
&& dateToCheck < y.EndDate)
.ToList();
if (x.Periods.Count > 0)
return x;
else
return null;
}).FirstOrDefault();
}
However, it only take the first array (ID: 1) of the JSON data and the first array of the Periods inside the JSON data, even the DateTime.Now is more than 2017-04-23 15:40 or it is 2017-04-23 15:52, it will return null.
Do I filtering not correct for the LINQ or in the between time condition?
Your answer much appreciated.
Second Update:
The expected output will be like:
Have the JSON data, which where the between date time is falling into, for example: between date time is falling into "ID: 2", and "Periods: 2017-04-23 15:57", then it will only return JSON of ID no 2 and falling Periods (in this case 2017-04-23 15:57 as StartDate, and 2017-04-23 16:00 as EndDate), while the rest of the Periods is removed. So it will be like this (It is based on the Periods, which where the date time is falling to, and it will determine which data need to get).
"ID" : "2",
"Title": "Second Title",
"Description": "Second Description",
"Periods": [ {
"StartDate": "2017-04-23 15:57",
"EndDate": "2017-04-23 16:00" }
Thanks
Problem with your query is TakeWhile, as per MSDN:-
Returns elements from a sequence as long as a specified condition is
true. The element's index is used in the logic of the predicate
function.
So in your query it is only checking untill it finds the correct match and after that it ignores all data. Instead you need to check your condition in entire periods.
You can simplify your query using FirstOrDefault and it should give you the correct result:-
return informations.FirstOrDefault(y => dateToCheck >= y.StartDate
& dateToCheck < y.EndDate);
This will return null if no match is found otherwise the first Information object if it finds a match.
If you want to return all matching Periods then use Where instaed and your method return type should change to IEnumerable<Information> instead of Information.
I think that instead of TakeWhile you need a Where:
x.Periods = x.Periods
.Where(y => dateToCheck >= y.StartDate
&& dateToCheck < y.EndDate)
.ToList();
Keep in mind that TakeWhile stops when the condition is false. If you need a more formal explanation, you can find here that:
The TakeWhile(IEnumerable, Func)
method tests each element of source by using predicate and yields the
element if the result is true. Enumeration stops when the predicate
function returns false for an element or when source contains no more
elements.
Update
private Information GetFirstMatchingInformationByPeriod(
List<Information> informations
, DateTime dateToCheck)
{
// Find the first information that match your search criteria
var information = informations.FirstOrDefault(information
=> information.Periods
.Any(period
=> period.dateToCheck >= period.StartDate
&& period.dateToCheck < period.EndDate);
// If not any found, return null.
if(information == null) return null;
var firstMatchingPeriod = information.Periods
.First(period => dateToCheck >= period.StartDate
&& dateToCheck < period.EndDate);
// Information found.
// Change it's periods with a List containin only the first matching period.
information.Periods = new List<Period>{ firstMatchingPeriod } ;
return information;
}
There is a much more readable way to write your query (that works):
private static Information GetData(List<Information> informations, DateTime dateToCheck)
{
return (from info in informations
from period in info.Periods
where dateToCheck >= period.StartDate &&
dateToCheck < period.EndDate
select info).FirstOrDefault();
}
I have a web application in which I'm retrieving some data into bootstrap table, what i want to do now is to use jQuery DataTable instead of the current as it has too much useful features.
Currently I'm retrieving the data from the server side using OOP approach, where a class object represents a data row in a particular table, and this object includes a dictionary which stores column names and values.
What I'm doing now is that I'm retrieving these class objects and append each dictionary of each object in a List<Item> and then serialize this list using JavaScriptSerializer object, and this object returns the following JSON format:
[
{
"slno":"2",
"status_message":"Lights still flashing",
"crm_services_id":"1", "subject_id":"Lights are flashing",
"severity_id":"5",
"user_id":"husain.alhamali",
"status_id":"1"
},
{
"slno":"3",
"status_message":"lights working fine",
"crm_services_id":"2",
"subject_id":"Lights are flashing",
"severity_id":"3",
"user_id":"husain.alhamali",
"status_id":"2"
}
]
When i tried to use this object to fill my DataTable AJAX I've got an error says:
Invalid JSON response
I saw some examples of a valid JSON response that is acceptable to a DataTable which is as follow:
{
"data": [
[
"Tiger Nixon",
"System Architect",
"Edinburgh",
"5421",
"2011/04/25",
"$320,800"
],
[
"Garrett Winters",
"Accountant",
"Tokyo",
"8422",
"2011/07/25",
"$170,750"
]
}
Now my question is is there any tool or plugin that could re-format my JSON string into an acceptable format like the one above?
With this HTML:
<table id="example"></table>
This JS will create a table:
var data = [{
"slno": "2",
"status_message": "Lights still flashing",
"crm_services_id": "1",
"subject_id": "Lights are flashing",
"severity_id": "5",
"user_id": "husain.alhamali",
"status_id": "1"
}, {
"slno": "3",
"status_message": "lights working fine",
"crm_services_id": "2",
"subject_id": "Lights are flashing",
"severity_id": "3",
"user_id": "husain.alhamali",
"status_id": "2"
}];
function getColumns(){
for(var i = 0; i < data.length; i++){
let columnsArray = [];
var keys = Object.keys(data[i]);
for(k in Object.keys(data[i])){
if(data[i].hasOwnProperty(keys[k])){
columnsArray.push({
"data":keys[k]
});
}
}
return columnsArray;
}
}
$(document).ready(function() {
var table = $('#example').DataTable({
"columns": getColumns(),
"data": data
});
});
Working example. Hope that helps.
dataTable require json data in return from ajax response having following keys
1. data
2. draw
3. recordsTotal
4. recordsFiltered
Use this:
var data = list.Select(u => u.GetType()
.GetProperties()
.Select(p => p.GetValue(u, null)));
example
public class User
{
public int userId { get; set; }
public string name { get; set; }
}
public class Programm
{
static void Main()
{
var list = new List<User>();
list.Add(new User
{
userId = 1,
name = "name 1",
});
list.Add(new User
{
userId = 2,
name = "name 2",
});
var data = list.Select(u => u.GetType()
.GetProperties()
.Select(p => p.GetValue(u, null)));
Console.WriteLine(new JavaScriptSerializer().Serialize(new
{
data = data
}));
}
}
result
{
"data" : [
["1", "name 1"],
["2", "name 2"]
]
}
This may be too basic of a question for SO, but I thought I would ask anyway.
I getting my feet wet with ElasticSearch and am trying to return a single document that has an exact match to my field of interest.
I have the field "StoryText" which is mapped as type "string" and indexed as "not_analyzed".
When I search using a the basic URI query:
123.456.0.789:9200/stories/storyphrases/_search?q=StoryText:"The boy sat quietly"
I return an exact matched document as I expected with a single hit.
However, when I use the search functionality:
GET 123.456.0.789:9200/stories/storyphrases/_search
{
"query" : {
"filtered" : {
"filter" : {
"term" : {
"StoryText" : "The boy sat quietly"
}
}
}
}
}
I get multiple documents returned with many hits (i.e. "The boy sat loudly", "The boy stood quietly" etc. etc.)
Could somebody help me to understand how I need to restructure my search request to mimic the result I get using the basic query parameter?
At present I am using NEST in C# to generate my search request which looks like this
var searchresults = client.Search<stories>(p => p
.Query(q => q
.Filtered(r => r
.Filter(s => s.Term("StoryText", inputtext))
)
)
);
Thanks very much for any and all reads and or thoughts!
UPDATE: Mappings are listed below
GET /stories/storyphrases/_mappings
{
"stories": {
"mappings": {
"storyphrases": {
"dynamic": "strict",
"properties": {
"#timestamp": {
"type": "date",
"format": "date_optional_time"
},
"#version": {
"type": "string"
},
"SubjectCode": {
"type": "string"
},
"VerbCode": {
"type": "string"
},
"LocationCode": {
"type": "string"
},
"BookCode": {
"type": "string"
},
"Route": {
"type": "string"
},
"StoryText": {
"type": "string",
"index": "not_analyzed"
},
"SourceType": {
"type": "string"
},
"host": {
"type": "string"
},
"message": {
"type": "string"
},
"path": {
"type": "string"
}
}
}
}
}
Mick
Well, first off you are executing two different queries here. The first is running in a query context whilst the second is essentially a match_all query executing in a filtered context. If your objective is simply to emulate the first query but by passing a JSON body you will need something like
GET 123.456.0.789:9200/stories/storyphrases/_search
{
"query" : {
"query_string" : {
"query" : "StoryText:'The boy sat quietly'"
}
}
}
To write this simple query using Nest you would use
var searchresults = client.Search<stories>(p => p.QueryString("StoryText:" + inputtext));
or in longer form
var searchresults = client.Search<stories>(p => p
.Query(q => q
.QueryString(qs => qs
.Query("StoryText:" + inputtext)
)
)
);
These both produce the same JSON body and send it to the _search endpoint. Assuming that storyphrases is your Elasticsearch type then you may also wish to include this in your C#.
var searchresults = client.Search<stories>(p => p
.Index("stories")
.Type("storyphrases")
.Query(q => q
.QueryString(qs => qs
.Query("StoryText:" + inputtext)
)
)
);
Having said all that and looking at your filtered query it should do what you expect according to my testing. Is your field definitely not analyzed? Can you post your mapping?
I am using MVC4 and C#.
I have a KendoUI Treeview and I'd like to populate it with data from RavenDB.
In the demo they use this:
public JsonResult Employees(int? id)
{
var dataContext = new NorthwindDataContext();
var employees = from e in dataContext.Employees
where (id.HasValue ? e.ReportsTo == id : e.ReportsTo == null)
select new {
id = e.EmployeeID,
Name = e.FirstName + " " + e.LastName,
hasChildren = e.Employees.Any()
};
return Json(employees, JsonRequestBehavior.AllowGet);
}
Notice the argument "id" - it's an int. In RavenDb document ID's are strings eg. myDco/231...
Imagine this is a standard document:
{
"CreationDate": "12/12/2012 8:07:59 PM",
"Name": "jkljklk",
"Type": "kljkljkljkljkl",
"Description": "ljkljklj",
"CreatedByUser": "ljklklkljklj",
"Deleted": false,
"Status": "NEW",
"Parent": "product/546"
}
How would I populate the treeview?
There should not be any problem to use string instead of that int. You just need to fetch the needed records depending on that string parameter passed to the Action method.
I figured this out.
I changed my RavenDB Document to include a list of all its children:
{
"CreationDate": "12/12/2012 9:33:34 PM",
"Name": "hohoho",
"Type": "hohohoh",
"Description": "hohohoh",
"CreatedByUser": "hohohoh",
"Deleted": false,
"Status": "NEW",
"Parent": "ohohohoh",
"Children": [
"item/1",
"item/2",
"item/3"
]
}
I then returned a list of my items to the View via the controller and then iterated through them, appending all the children to their correct parent nodes:
#(Html.Kendo().TreeView().Name("TreeView").DragAndDrop(true)
.Items(treeview =>
{
foreach (var myItem in Model)
{
var myItemName = myItem.Name;
var children = myItem.Children;
treeview.Add().Text(myItemName ).Expanded(false).Items(branch =>
{
if (children != null)
{
foreach (var child in children)
{
branch.Add().Text(child);
}
}
});
}
}
))
Anyway, thanks for the responses :)
Hope this helps someone else one day.