I have two JSONs files Country & Ceremony
Country JSON:
[
{
"Short": "AF",
"Name": "Afghanistan"
},
{
"Short": "AN",
"Name": "Netherlands Antilles"
},
{
"Short": "AI",
"Name": "Anguilla"
},
{
"Short": "AL",
"Name": "Albania"
} ]
Ceremony JSON:
[
{
"CName": "Fitr",
"CStart": "2021-11-10T09:00:00",
"CEnd": "2021-11-14T09:00:00",
"Loc": {
"Info": "",
"Short": "AF"
}
},
{
"CName": "Azha",
"CStart": "2023-06-17T09:18:44",
"CEnd": "2023-06-18T09:18:44",
"Loc": {
"Info": "",
"Short": "AI"
}
},
{
"CName": "Azha",
"CStart": "2022-01-05T00:00:00",
"CEnd": "2022-01-05T23:59:59",
"Loc": {
"Info": "",
"Short": "AL"
}
},
{
"CName": "Fitr",
"CStart": "2022-01-05T00:00:00",
"CEnd": "2022-01-05T23:59:59",
"Loc": {
"Info": "",
"Short": "AN",
}
}
]
Country Model Class
public class Country
{
public string Short{ get; set; }
public string Name { get; set; }
}
Ceremony Model Class
public class Ceremony
{
public string CName { get; set; }
public DateTime CStart { get; set; }
public DateTime End { get; set; }
public Loc loc { get; set; }
}
Loc Model Class
public class Loc
{
public string Info { get; set; }
public string Short { get; set; }
}
I want to show Country (Name) with a connection to Ceremony, Loc, and Short, so that when I read the Ceremony data in front of Short, I can see the full name of the country. Country full name should come from Country JSON.
Results should be like this:
CName CStart CEnd Short Name
Fitr "" "" AF Afghanistan
Azha "" "" AI Anguilla
How can I use LINQ to display the top countries i.e., using (Short) with the most ceremonies in 2021?
You can join two entities on ShortName like below :
var countries = ...;
var ceremonies = ...;
var result = (from c in countries
join ce in ceremonies on c.Short equals ce.loc.Short
select new {
ce.CName,
ce.CStart,
ce.Cend,
c.Short,
c.Name
}).Where(r=> r.CStart.Year == 2021).
GroupBy(r=> r.Short).Select(r=> new { Short = r.Key,
EventCount = r.Count()}).OrderByDescending(r=> r.EventCount)
.ToArray();
Edit
Added grouping and sorting as the question evolves.
Related
I have list of User and Department Like below:
public class Users
{
public int id { get; set; }
public string jobTitle { get; set; }
public int officeLocation { get; set; }
public string userPrincipalName { get; set; }
}
public class Departments
{
public int id { get; set; }
public string department { get; set; }
public string displayName { get; set; }
}
Here is my Json
"Departments": [
{
"department": "Azure",
"id": "1",
"displayName": "Thad"
},
{
"department": "Visual Studio",
"id": "2",
"displayName": "Scott Hansalman"
},
{
"department": "C#",
"id": "3",
"displayName": "Paul"
}
]
"Users": [
{
"jobTitle": "Senior Program manager ",
"officeLocation": "Redmond",
"userPrincipalName": "thad.teams.com",
"id": "1"
},
{
"jobTitle": ""Technical Lead,
"officeLocation": "Redmond",
"userPrincipalName": "scott.teams.com",
"id": "2"
},
{
"jobTitle": "Development Engineer II",
"officeLocation": "Canada",
"userPrincipalName": "paul.teams.com",
"id": "3"
}
]
I want to join two list using linq where I would pass id of user
and get department.
I tried like this
var query = from user in Users
join dept in Departments
on user.id equals dept.id
select new
{
user.id ,
user.jobTitle,
user.officeLocation,
dept.department
}.where(id = 1) ;
But where clause doesn't seems okay, say's where doesn't exits in current context
This will work, you're just missing some ( )s, and there is a syntax error in the where...
(from user in Users
join dept in Departments
on user.id equals dept.id
select new
{
user.id ,
user.jobTitle,
user.officeLocation,
dept.department
}).Where(c => c.id == 1) ;
But usually, the Where is done upfront, as query expression.
How could I find a specific id in this list?
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
contactList.contacts.FindAll(x => x.id == item.id);
The code above is not filtering by id and is returning all rows from object.
(Visual Studio is not showing me .Where clause only .Find and .FindAll)
C# code
namespace RestDemo.Model
{
public class Phone
{
public string mobile { get; set; }
public string home { get; set; }
public string office { get; set; }
}
public class Contact
{
public int id { get; set; }
public string name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string gender { get; set; }
public Phone phone { get; set; }
}
public class ContactList
{
public List<Contact> contacts { get; set; }
}
}
Json:
{ "contacts": [ { "id": 200, "name": "Ravi Tamada", "email": "ravi#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } }, { "id": 201, "name": "Klev Krist", "email": "klev#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } }, { "id": 202, "name": "Paul Neil", "email": "paul.neil#gmail.com", "address": "xx-xx-xxxx,x - street, x - country", "gender": "male", "phone": { "mobile": "+91 0000000000", "home": "00 000000", "office": "00 000000" } } ]}
Thanks
The FindAll method does not assign an object to the search result.
You have to keep the search result somewhere.
Example Multi Result
If you are expecting multiple results
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var findedContact = contactList.contacts.FindAll(x => x.id == item.id);
//You business codes..
Example Single Result
If you are only waiting for 1 result
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var oneContact = contactList.contacts.Find(x => x.id == item.id);
if(oneContact ==null){
//not found business codes
}
else {
//find result business codes
}
Assuming you want to find a certain id, we'll call it
var idToFind = "myID";
To find all contacts with said ID:
var contacts = contactList.contacts.Where(contact=> contact.id == idToFind);
To find at least one contact with said ID:
var contactWithID = contactList.contacts.FirstOrDefault(contact=> contact.id == idToFind);
// Before using, check if null, means no contact matched the id.
if(contactWithID != null)
{
// A contact was found.
}
else
{
// No contact matching that id is found.
}
Specific to your case, I am using the same Model structure to deserialize your JSON and then use the Where linq clause to achieve what you require. A working fiddle can be found at: https://dotnetfiddle.net/SAcFja
Code:
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var jsonString = #"{ 'contacts': [{ 'id': 200, 'name': 'Ravi Tamada', 'email': 'ravi#gmail.com', 'address': 'xx-xx-xxxx,x - street, x - country', 'gender': 'male', 'phone': { 'mobile': '+91 0000000000', 'home': '00 000000', 'office': '00 000000' } }] }";
var data= JsonConvert.DeserializeObject<ContactList>(jsonString);
//Console.WriteLine(data.contacts);
var found=data.contacts.Where(x=>x.id.ToString()=="200");
foreach(var value in found)
{
Console.WriteLine(value.id);
Console.WriteLine(value.address);
}
}
}
public class Phone
{
public string mobile { get; set; }
public string home { get; set; }
public string office { get; set; }
}
public class Contact
{
public string id { get; set; }
public string name { get; set; }
public string email { get; set; }
public string address { get; set; }
public string gender { get; set; }
public Phone phone { get; set; }
}
public class ContactList
{
public List<Contact> contacts { get; set; }
}
Output when id=200:
200
xx-xx-xxxx,x - street, x - country
As per your comment on #Tenretni's answer, I guess you missed to use System.Linq library in your code.
Import System.Collections.Generic and System.Linq in your code and use FirstOrDefault() or .Where() clause
using System.Collections.Generic;
using System.Linq;
//…
string jsonString = #"{ 'contacts': [{ 'id': 'c200', 'name': 'Ravi Tamada', 'email': 'ravi#gmail.com', 'address': 'xx-xx-xxxx,x - street, x - country', 'gender': 'male', 'phone': { 'mobile': '+91 0000000000', 'home': '00 000000', 'office': '00 000000' } }] }";
var contactList = JsonConvert.DeserializeObject<ContactList>(jsonString);
var item = "c200";
var result = contactList.contacts.FirstOrDefault(x => x.id == item);
Console.WriteLine(result.name);
//If you have multiple records with same ID then you can try where clause
var result = contactList.contacts.Where(x => x.id == item); //Here result will be list of Contact
.Net Fiddle
I have a problem with my C# code. I can't produce my JSON well.
I'm using NHIBERNATE to connect and select data from my SQL Server. I want to produce a JSON with a list object inside it. Need your help guys.
NHibernate code:
var query = (from partners in session.Query<Partners>()
join partnerUsers in session.Query<PartnerUsers>() on partners.PartnerId equals partnerUsers.PartnerId
where partners.PartnerId == partnerId
select new Partnersss
{
PartnerId = partners.PartnerId,
PartnerName = partners.Name,
PartnerUsers = new PartnerUsersss()
{
LoginId = partnerUsers.LoginId
}
}).ToList<object>();
return query;
Class:
public class PartnerUsersss
{
public int PartnerUserId { get; set; }
public string LoginId { get; set; }
}
public class Partnersss
{
public int PartnerId { get; set; }
public string PartnerName { get; set; }
public PartnerUsersss PartnerUsers { get; set; }
}
JSON result:
{
"Data": "",
"data": [{
"PartnerId": 1,
"PartnerName": "ExpressPay",
"PartnerUsers": {
"PartnerUserId": "0",
"LoginId": "a#a.com"
}
}, {
"PartnerId": 1,
"PartnerName": "ExpressPay",
"PartnerUsers": {
"PartnerUserId": "0",
"LoginId": "b#b.com"
}
}],
"ResponseCode": "0",
"ResponseMessage": "Successful"
}
But I want to be able to produce this JSON instead:
{
"Data": "",
"data": [{
"PartnerId ": 1,
"PartnerName": "ExpressPay ",
"PartnerUsers": [{
"partnerUserId": "0",
"loginId": "a#a.com"
}, {
"partnerUserId": "0",
"loginId": "b#b.com"
}]
}],
"ResponseCode": "0",
"ResponseMessage": "Successful"
}
I tried using List with this kind of code
PartnerUsers = new List<PartnerUsersss>
and also change the class. But I got an error
List does not contain a definition for LoginId
In new class:
public List<PartnerUsersss> PartnerUsers { get; set; }
You need to remove join from your query and modify your query like below,
var query = (from partners in session.Query<Partners>()
where partners.PartnerId == partnerId
let partnerUsers = (from pu in session.Query<PartnerUsers>()
where pu.PartnerId == partners.PartnerId
select pu).ToList()
select new Partnersss
{
PartnerId = partners.PartnerId,
PartnerName = partners.Name,
PartnerUsers = partnerUsers
}).ToList();
You need to change the type of PartnerUsers property to List,
public List<PartnerUsersss> PartnerUsers { get; set; }
I have the following json structure that I am getting from an api:
{
"event_instance": [
{
"id": 55551244,
"event_id": 11112,
"name": "Brown Belt Karate Class",
"staff_members": [
{
"id": 12345,
"name": "John Smith"
}
],
"people": [
{
"id": 111,
"name": "Jane Doe"
},
{
"id": 222,
"name": "Josh Smith"
},
{
"id": 333,
"name": "Ben Johnson"
}
],
"visits": [
{
"id": 1234578,
"person_id": 111,
"state": "completed",
"status": "complete"
},
{
"id": 1239865,
"person_id": 222,
"state": "completed",
"status": "complete"
},
{
"id": 1239865,
"person_id": 333,
"state": "canceled",
"status": "cancel"
}
]
}
]
}
I am deserializing this into the following .net objects using JSON.NET:
[JsonObjectAttribute("event_instance")]
public class EventInstance
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("event_id")]
public int EventId { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
[JsonPropertyAttribute("staff_members")]
public List<StaffMember> StaffMembers { get; set; }
[JsonPropertyAttribute("visits")]
public List<Visit> Visits { get; set; }
[JsonPropertyAttribute("people")]
public List<Student> Students { get; set; }
}
[JsonObjectAttribute("staff_members")]
public class StaffMember
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
}
[JsonObjectAttribute("people")]
public class People
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("name")]
public string Name { get; set; }
}
[JsonObjectAttribute("visits")]
public class Visits
{
[JsonPropertyAttribute("id")]
public int Id { get; set; }
[JsonPropertyAttribute("person_id")]
public int PersonId { get; set; }
[JsonPropertyAttribute("state")]
public string State { get; set; }
[JsonPropertyAttribute("status")]
public string Status { get; set; }
}
I am using the following code to de-serialize:
var event = (EventInstance)JsonConvert.DeserializeObject(json, typeof(EventInstance));
The above works fine and gives me an accurate object representation of the above json structure. Now I am trying to query this event object to filter/project to a new structure that I can then serialize back to json and send down to the browser. I need to return a list of students for the event that are in a state of "completed" and a status of "complete". As you can see, the people array ties to the visits array (with id and person_id). I would like to produce the following simple output:
11112, Brown Belt Karate Class, John Smith, 111, Jane Doe
11112, Brown Belt Karate Class, John Smith, 222, Josh Smith
I have tried something like this:
var studentList = from theClass in event
from staff in theClass.StaffMembers
from student in theClass.People
from visits in theClass.Visits
where visits.Status == "complete"
&& visits.State == "completed"
select new
{
event_id = theClass.EventId
class_name = theClass.Name,
instructor_name = staff.Name,
student_id = student.Id,
student_name = student.Name
};
string _data = JsonConvert.SerializeObject(studentList);
Naturally this produces duplicate student names. I am new to linq. Basically I need to join/tie the people and visits array so I just get back a single student for that id, along with the root data for this event. Any advice on a better way to do this is much appreciated too!
The trick is to join the students and visits into a collection that contains data of both:
from ei in eventInstances
from sm in ei.StaffMembers
from x in
(from vi in ei.Visits
join st in ei.Students on vi.PersonId equals st.Id
select new { vi, st }) // Here you get students and visits side-by-side
select new
{
ei.EventId,
Event = ei.Name,
StaffMemeber = sm.Name,
PersonId = x.st.Id,
Student = x.st.Name
}
I want to deserialize JSON data (using Newtonsoft) similar to following, and convert to a strongly-typed object/list in C#, but can't figure out how to define the class such that indexed references are converted to the referenced objects.
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"Author": 0,
"Title": "Another good read",
"PublishedCountries": "0,1",
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}
Ideally, I'd like to use classes similar to following:
public class Country
{
public string Name { get; set;}
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public IEnumerable<Country> PublishedCountries { get; set; }
}
public class ListOfBooks
{
public IEnumerable<Book> Books { get; set; }
}
And deserialize like this:
var listOfBooks = JsonConvert.DeserializeObject<ListOfBooks>(jsonAsString);
I'm stuck as how to tell Json.Net that the Author property in the book JObject is an index, rather than an integer. Same goes for the PublishedCountries (that's comma-separated list of indexes)
I can't see a way other than helping the deserialization process a little bit.
var dynObj = (JObject)JsonConvert.DeserializeObject(json);
var authors = dynObj["Authors"]
.Select(j => new AuthorDetails {
RealName = (string)j["RealName"],
DisplayName = (string)j["DisplayName"]
})
.ToList();
var countries = dynObj["Countries"]
.Select(j => new Country { Name = (string)j["Name"]})
.ToList();
var books = dynObj["Books"].Select(x => new Book
{
Author = authors[(int)x["Author"]],
Title = (string)x["Title"],
PublishedCountries = x["PublishedCountries"].ToString().Split(',')
.Select(i =>countries[int.Parse(i)])
.ToList()
})
.ToList();
public class Country
{
public string Name { get; set; }
}
public class AuthorDetails
{
public string DisplayName { get; set; }
public string RealName { get; set; }
}
public class Book
{
public AuthorDetails Author { get; set; }
public string Title { get; set; }
public List<Country> PublishedCountries { get; set; }
}
I believe what you want to do is 'preserve object references'.
You can mark-up your C# object with attributes to describe when to utilise a reference, rather than duplicate the content of the object all over again:
[JsonObject(IsReference = true)] (use on the type declaration)
However, your generated Javascript will not look quite like what you have demonstrated, take a look here to see how to do it.
http://james.newtonking.com/projects/json/help/?topic=html/PreserveObjectReferences.htm
Instead, your JSON will look more like this:
{
"Countries": [
{
"Name": "USA",
},
{
"Name": "UK",
},
{
"Name": "JAPAN",
},
],
"Authors": [
{
"DisplayName": "John Doe",
"RealName": "Not John Doe"
},
{
"DisplayName": "Jane Doe",
"RealName": "Not Jane Doe"
},
],
"Books": [
{
"$id": 1,
"Author": 0,
"Title": "A good read",
"PublishedCountries": "0,1",
},
{
"$ref": 1
},
{
"Author": 1,
"Title": "This one is even better",
"PublishedCountries": "0,1,2",
},
],
}