Add new record var LINQ - c#

I am trying to add a new record to the var "issue". I get a list of XXX from a SQL server DB and return in as follows for a jTable grid:
public dynamic XXXList(int CCC)
{
try
{
var issue = db.XXX.ToList().
Select(c => new { DisplayText = c.AAA, Value = c.BBB, c.CCC}).
Where(h => h.HHH == JJJ);
return (new { Result = "OK", Options = issue });
}
catch (Exception ex)
{
return (new { Result = "ERROR", Message = ex.Message });
}
}
The function returns:
{
"$id": "1",
"Result": "OK",
"Options": [
{
"$id": "2",
"DisplayText": "Food and Beverages",
"Value": 4,
"CCC": 4
},
{
"$id": "3",
"DisplayText": "Wrong software versions",
"Value": 5,
"CCC": 4
}
]
}
How can I add another record to the issue var before returning it?
Example:
{
"DisplayText": "new display text",
"Value": 5,
"CCC": 4
}
EDIT:
Here is my function after applying the answers:
public dynamic XXXList(int CCC)
{
try
{
var newRecord = new[] { new { DisplayText = "None", Value = -1, CCC = -1} };
var issue = db.ProjectXXXs.Where(h => h.CCC == JJJ).Select(c => new { DisplayText = c.AAA, Value = c.BBB, c.CCC }).ToList().Concat(newRecord);
return (new { Result = "OK", Options = issue });
}
catch (Exception ex)
{
return (new { Result = "ERROR", Message = ex.Message });
}
}
Thank you very much for all the help.

Concatenate any additional items:
var additional = new[] {new { DisplayText = ..., Value = ..., CCC = ... },
new { DisplayText = ..., Value = ..., CCC = ... }};
var issue = db.XXX.
Where(h => h.HHH == JJJ).
Select(c => new { DisplayText = c.AAA, Value = c.BBB, c.CCC}).
ToList().
Concat(additional);
(EDIT: Credit for the reordering of Where, Select and ToList goes to James Curran.)

Well first thing you want to do is move the ToList() to the end. With the ToList where it was, you'd read every column from every record from the Database, build a list from that, and then search it. With the ToList at the end, you send a query for just those columns of that record to the database, and then build a list from what comes back. You'll also need to move the Where before the Select, so it applies to the XXX records and not the output from the select.
var issue = db.XXX
.Where(h => h.HHH == JJJ)
.Select(c => new { DisplayText = c.AAA, Value = c.BBB, c.CCC})
.ToList();
From here the Add or Concat options suggested by other should work, however, you may have to use a named class instead of an anonomous one.
class OptionValues
{
public string DisplayText {get; set;}
public int Value {get; set;}
public int CCC {get; set;}
}
// :
// :
.Select(c => new OptionValues {DisplayText = c.AAA, Value = c.BBB, CCC= c.CCC})

I'm not sure, but can't you just write a line under var issue:
issue.Add(new { });
with the values that you want of course.

Related

How can I select the value and type of a dynamic list?

I have a dynamic query that brings me dynamic columns (System.Linq.Dynamic.Core):
var data = data.Select("new (col1, col2, col3)", "T", StringComparison.OrdinalIgnoreCase);
[
{ col1: "This", col2: 1.56, col3: "Something else" }
]
Now I need to bring the type of each column. ex:
[
{
col1: { value: "This", type: "string" },
col2: { value: 1.56, type: "decimal" }
}
]
To get that, I was thinking of something like:
var rows = data.Select(x => new {
Type = MyHelper.GetType(x),
Value = x
});
But that it's not working.
An unhandled error occurred The best overloaded method match for
'MyHelper.GetType(System.Reflection.PropertyInfo)' has some invalid
arguments
I do know how to get the type
public static string GetType(PropertyInfo type)
{
return type.PropertyType.IsGenericType && type.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>) ? type.PropertyType.GetGenericArguments()[0].ToString().Replace("System.", "") : type.PropertyType.Name;
}
But I don't know how to build the query.
[UPDATE]
This is a try, but not what I need
var rows = data.Select(x => new {
Type = MyHelper.GetType(x.GetType()),
Value = x
});
[
{
"type": "<>f__AnonymousType0`3",
"value": {
"col1": "2019-10-15T00:00:00",
"col2": 0.00,
"col3": "abc"
}
},
]
Here is a working demo you could refer to:
public List<object> Get(int id)
{
var data = new List<Object>
{
new{
col1="aaa",
col2= 1.25,
col3 = 1
},
new{
col2="asd",
col3= 1.2,
col4 =2
}
};
var aaa = new List<object>() { };
foreach (var item in data)
{
var ds = item.GetType().GetProperties();
foreach(var i in ds)
{
var name = i.Name;
var type = i.PropertyType.Name;
var value = item.GetType().GetProperty(name).GetValue(item);
aaa.Add(new { name=name, type = type, value = value });
}
}
return aaa;
}

Formatting api JSON response to add attributes to an array

I have the following api controller that returns a json representation of the query you see here:
public async Task<ActionResult<IEnumerable<CarDto>>> GetCarData(Guid carID)
{
var carData = await (from cl in _context.CarList
join tl in _context.transmissionList
on cl.CId equals tl.CId
join to in _context.transmissionOptions
on tl.TId equals to.TId
where cl.CId == carID
select new CarDto
{
CarId = cl.CarId,
TransmissionId = tl.TId,
OptionId = to.OptionId,
GearId = to.GearId
})
.ToListAsync();
return carData;
}
The returned json data looks like this:
[
{
"carId": "351a",
"transmissionId": "ec7",
"optionId": "a1",
"gearId": "674532a"
},
{
"carId": "351a",
"transmissionId": "ec7",
"optionId": "b7",
"gearId": "5f9173f"
},
{
"carId": "351a",
"transmissionId": "ec7",
"optionId": "c5",
"gearId": "cf807"
}
]
However, I'd like for it to be formatted such that there is a property called transmissionChoices that contains an array of the possible options.
Like this:
{
"carId": "351a",
"transmissionId": "ec7",
"transmissionChoices": [
{
"optionId": "a1",
"gearId": "674532a"
},
{
"optionId": "b7",
"gearId": "5f9173f"
},
{
"optionId": "c5",
"gearId": "cf807"
}
]
}
Is there a way to get the controller to format it like that?
You can use the LINQ GroupBy method and then project the grouped results into the shape you want.
public async Task<ActionResult<IEnumerable<object>>> GetCarData(Guid carID)
{
var carData = await (from cl in _context.CarList
join tl in _context.transmissionList
on cl.CId equals tl.CId
join to in _context.transmissionOptions
on tl.TId equals to.TId
where cl.CId == carID
select new
{
CarId = cl.CarId,
TransmissionId = tl.TId,
OptionId = to.OptionId,
GearId = to.GearId
})
.GroupBy(x => x.CarId)
.Select(g => new
{
CarId = g.First().CarId,
TransmissionId = g.First().TransmissionId,
TransmissionChoices = g.Select(x => new
{
OptionId = x.OptionId,
GearId = x.GearId
})
})
.ToListAsync();
return carData;
}
Note that this is projecting the results into an anonymous type. Feel free to create a model that matches the schema you need and then use that model in the Select(...) projection.

NEST compound queries which must all be satisfied

var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo);
var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom);
var nameField = Infer.Field<Project>(f => f.Contact.Name);
var active_date_to = new DateRangeQuery(){
Name = "toDate",
Boost = 1.1,
Field = "availablity.availableTo",
GreaterThan = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
var active_date_from = new DateRangeQuery(){
Name = "from",
Boost = 1.1,
Field = "availablity.availableFrom",
LessThanOrEqualTo = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
public ISearchResult<Project> Search(SearchCriteria criteria)
{var ret = _client.Search<Project>(s =>
s.Query(q =>
active_date_from &&
active_date_to &&
q.Match(d => d.Query(criteria.FreeText))
).From(criteria.CurrentPage).Size(criteria.Take)
.From(criteria.CurrentPage)
.Take(criteria.Take)
);
result.Total = ret.Total;
result.Page = criteria.CurrentPage;
result.PerPage = criteria.Take;
result.Results = ret.Documents;
return result;
}
what im trying to do is get the results matching the freetext but are also withing the pricerange..
somehow though what i get is an invalid NEST response build from a unsuccessful low level call on POST... and in consequence an empty query.
there are no compiling errors.
does anyone have an idea where i could have gone wrong or what im missing?
the other thing i tried was
var mustClauses = new List<QueryContainer>();
mustClauses.Add(active_date_from);
mustClauses.Add(active_date_to);
mustClauses.Add(new TermQuery
{
Field = "contact.name",
Value = criteria.FreeText
});
var searchRequest = new SearchRequest<Project>()
{
Size = 10,
From = 0,
Query = new BoolQuery
{
Must = mustClauses
}
};
var ret = _client.Search<Project>(searchRequest);
result.Total = ret.Total;
result.Page = criteria.CurrentPage;
result.PerPage = criteria.Take;
result.Results = ret.Documents;
which got me pretty much the same results.. (read: none)
is there something im missing?
edit:
however.. this:
var ret = _client.Search<Project>(s => s.Query(q => q.Match(m => m.Field(f => f.DisplayName).Query(criteria.FreeText))));
gives me exactly what i want (without the validation of the dates of course and only looking at one field)
In your first example, the match query is missing a field property which is needed for the query. Because of NEST's conditionless query behaviour, the query is not serialized as part of the request. The two date range queries are serialized however.
Here's a simple example that you may find useful to get the correct query you're looking for
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "projects";
var connectionSettings = new ConnectionSettings(pool, new InMemoryConnection())
.DefaultIndex(defaultIndex )
.PrettyJson()
.DisableDirectStreaming()
.OnRequestCompleted(response =>
{
if (response.RequestBodyInBytes != null)
{
Console.WriteLine(
$"{response.HttpMethod} {response.Uri} \n" +
$"{Encoding.UTF8.GetString(response.RequestBodyInBytes)}");
}
else
{
Console.WriteLine($"{response.HttpMethod} {response.Uri}");
}
Console.WriteLine();
if (response.ResponseBodyInBytes != null)
{
Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
$"{Encoding.UTF8.GetString(response.ResponseBodyInBytes)}\n" +
$"{new string('-', 30)}\n");
}
else
{
Console.WriteLine($"Status: {response.HttpStatusCode}\n" +
$"{new string('-', 30)}\n");
}
});
var client = new ElasticClient(connectionSettings);
var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo);
var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom);
var nameField = Infer.Field<Project>(f => f.Contact.Name);
var active_date_to = new DateRangeQuery
{
Name = "toDate",
Boost = 1.1,
Field = availableToField,
GreaterThan = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
var active_date_from = new DateRangeQuery
{
Name = "from",
Boost = 1.1,
Field = availableFromField,
LessThanOrEqualTo = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
var ret = client.Search<Project>(s => s
.Query(q =>
active_date_from &&
active_date_to && q
.Match(d => d
.Query("free text")
)
)
.From(0)
.Size(10)
);
}
public class Project
{
public Availibility Availablity { get; set; }
public Contact Contact { get; set; }
}
public class Contact
{
public string Name { get; set; }
}
public class Availibility
{
public DateTime AvailableFrom { get; set; }
public DateTime AvailableTo { get; set; }
}
Your current query generates
POST http://localhost:9200/projects/project/_search?pretty=true
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"range": {
"availablity.availableFrom": {
"lte": "2017-07-21T10:01:01.456794+10:00",
"time_zone": "+01:00",
"format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy",
"_name": "from",
"boost": 1.1
}
}
},
{
"range": {
"availablity.availableTo": {
"gt": "2017-07-21T10:01:01.456794+10:00",
"time_zone": "+01:00",
"format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy",
"_name": "toDate",
"boost": 1.1
}
}
}
]
}
}
}
If a nameField is added as the field for the match query you get
POST http://localhost:9200/projects/project/_search?pretty=true
{
"from": 0,
"size": 10,
"query": {
"bool": {
"must": [
{
"range": {
"availablity.availableFrom": {
"lte": "2017-07-21T10:02:23.896385+10:00",
"time_zone": "+01:00",
"format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy",
"_name": "from",
"boost": 1.1
}
}
},
{
"range": {
"availablity.availableTo": {
"gt": "2017-07-21T10:02:23.896385+10:00",
"time_zone": "+01:00",
"format": "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy",
"_name": "toDate",
"boost": 1.1
}
}
},
{
"match": {
"contact.name": {
"query": "free text"
}
}
}
]
}
}
}
Remove InMemoryConnection from ConnectionSettings if you actually want to execute the query against Elasticsearch and see the results.
The range query is a structured query where a document either matches or doesn't match the predicate. Because of this, it can be wrapped in a bool query filter clause which will forgo calculating a score for it and perform better. Because no scoring occurs, boost is not needed.
Putting this together
var availableToField = Infer.Field<Project>(f => f.Availablity.AvailableTo);
var availableFromField = Infer.Field<Project>(f => f.Availablity.AvailableFrom);
var nameField = Infer.Field<Project>(f => f.Contact.Name);
var active_date_to = new DateRangeQuery
{
Name = "toDate",
Field = availableToField,
GreaterThan = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
var active_date_from = new DateRangeQuery
{
Name = "from",
Field = availableFromField,
LessThanOrEqualTo = DateTime.Now,
TimeZone = "+01:00",
Format = "yyyy-MM-ddTHH:mm:SS||dd.MM.yyyy"
};
var ret = client.Search<Project>(s => s
.Query(q =>
+active_date_from &&
+active_date_to && q
.Match(d => d
.Field(nameField)
.Query("free text")
)
)
.From(0)
.Size(10)
);
You may also want to explore modelling available from and to as a date_range type

how to query data limit in one type using nest elasticsearch

in NEST 2.x, I wrote code to query data like below:
var query = new QueryContainer();
query = query && new TermQuery { Field = "catId", Value = catId };
query = query && new NumericRangeQuery { Field ="price", GreaterThan = 10 };
var request =new SearchRequest<Project>
{
From = 0,
Size = 100,
Query = query,
Sort = new List<ISort>
{
new SortField { Field = "field", Order = SortOrder.Descending },
...
},
Type?? //problem comes here, how to specify type??
}
var response = _client.Search<Project>(request);
There are more than one type in my index, I want to query data in one of type.(just like query one of table data in a database), I hope in the SearchRequest object initializer have a "Type" parameter.
You can specify the indices and types in the constructor for SearchRequest<T>()
var catId = 1;
var query = new QueryContainer(new TermQuery { Field = "catId", Value = catId });
query = query && new NumericRangeQuery { Field = "price", GreaterThan = 10 };
var request = new SearchRequest<Project>("index-name", Types.Type(typeof(Project), typeof(AnotherProject)))
{
From = 0,
Size = 100,
Query = query,
Sort = new List<ISort>
{
new SortField { Field = "field", Order = Nest.SortOrder.Descending },
}
};
var response = client.Search<Project>(request);
would generate the following query
POST http://localhost:9200/index-name/project%2Canotherproject/_search?pretty=true
{
"from": 0,
"size": 100,
"sort": [
{
"field": {
"order": "desc"
}
}
],
"query": {
"bool": {
"must": [
{
"term": {
"catId": {
"value": 1
}
}
},
{
"range": {
"price": {
"gt": 10.0
}
}
}
]
}
}
}

Create nested json with c#

I am able to create a flat serialized JSON string pretty easily with c#
My issue is I want to create a nested string like this below
[ {
title: "Yes",
id : "1",
menu: [ {
title: "Maybe",
id : "3",
alert : "No",
menu: [ {
title: "Maybe Not",
id : "8",
alert : "No",
menu: []
} ]
} ]
},
{
title: "No",
id : "2",
menu: []
}]
Any help would be great
Are you using MVC 3? - Do something like:
return Json(myObectWithListProperties, JsonRequestBehavior.AllowGet);
I use this to return complex C# objects that match the structure of the JavaScript objects I want.
e.g.:
var bob = new {
name = "test",
orders = new [] {
new { itemNo = 1, description = "desc" },
new { itemNo = 2, description = "desc2" }
}
};
return Json(bob, JsonRequestBehavior.AllowGet);
gives:
{
"name": "test",
"orders": [
{
"itemNo": 1,
"description": "desc"
},
{
"itemNo": 2,
"description": "desc2"
}
]
}
EDIT: A bit more nesting for fun:
var bob = new {
name = "test",
orders = new [] {
new { itemNo = 1, description = "desc" },
new { itemNo = 2, description = "desc2" }
},
test = new {
a = new {
b = new {
something = "testing",
someOtherThing = new {
aProperty = "1",
another = "2",
theThird = new {
bob = "quiteDeepNesting"
}
}
}
}
}
};
return Json(bob, JsonRequestBehavior.AllowGet);
gives:
{
"name": "test",
"orders": [
{
"itemNo": 1,
"description": "desc"
},
{
"itemNo": 2,
"description": "desc2"
}
],
"test": {
"a": {
"b": {
"something": "testing",
"someOtherThing": {
"aProperty": "1",
"another": "2",
"theThird": {
"bob": "quiteDeepNesting"
}
}
}
}
}
}
Try using
using System.Web.Script.Serialization;
//Assumed code to connect to a DB and get data out using a Reader goes here
Object data = new {
a = reader.GetString(field1),
b = reader.GetString(field2),
c = reader.GetString(field3)
};
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
string json = javaScriptSerializer.Serialize(data);
This is built-in and saves you the work of serializing to JSON yourself!
This example assumes you are getting data from a database using some sort of reader, and it then constructs the object you want to serialize using an anonymous class. Your anonymous class can be as simple or complex as you need it to be and the JavaScriptSerializer will handle transforming it to JSON. This approach is also useful because you can easily control the JSON property names it will create in the JSON.
using System.Web.Script.Serialization;
var strNJson = new
{
to = "hello",
notification = new
{
title = "textTitle",
body = "bodyText"
}
};
JavaScriptSerializer javaScriptSerializer = new JavaScriptSerializer();
string json = javaScriptSerializer.Serialize(strNJson);
{ "to":"hello",
"notification": {
"title":"titleText",
"body":"bodyText"
}
}
You can make use of the ExpandoObject under the System.Dynamic namespace.
Here is a small snippet for achieving your solution:
dynamic parameters = new dynamic[2];
parameters[0] = new ExpandoObject();
parameters[0].title = "Yes";
parameters[0].id = "1";
parameters[0].menu = new dynamic[1];
parameters[0].menu[0] = new ExpandoObject();
parameters[0].menu[0].title = "Maybe";
parameters[0].menu[0].id = "3";
parameters[0].menu[0].alert = "No";
parameters[0].menu[0].menu = new dynamic[1];
parameters[0].menu[0].menu[0] = new ExpandoObject();
parameters[0].menu[0].menu[0].title = "Maybe Not";
parameters[0].menu[0].menu[0].id = "8";
parameters[0].menu[0].menu[0].alert = "No";
parameters[0].menu[0].menu[0].menu = new dynamic[0];
parameters[1] = new ExpandoObject();
parameters[1].title = "No";
parameters[1].id = "2";
parameters[1].menu = new dynamic[0];
string json = JsonConvert.SerializeObject(parameters, Formatting.Indented);
Console.WriteLine(json);
Here is the work in fiddle
Note: There are other ways to achieve this, but I have been using this approach.

Categories

Resources