"Cannot access child value on Newtonsoft.Json.Linq.JValue" - c#

My JSON File
{"data":
[
{"id":"1","user_code":"C016482","name":"CART 1","details":"[{\"Id\":15476,\"Name2\":\"AQUAFRESHIG TEETH (6+)\",\"SalesPriceVM\":250,\"DiscountPercentVM\":0,\"product_quantity\":3,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=15476\"},{\"Id\":22514,\"Name2\":\"BABE ANTI OILY DANDRUFF SHAMPOO 250 ML\",\"SalesPriceVM\":1800,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=22514\"},{\"Id\":19886,\"Name2\":\"ALOE VERA GEL\",\"SalesPriceVM\":1674,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=19886\"}]","created_at":"2020-05-20 11:52:49","updated_at":"2020-05-20 11:52:49"},
{"id":"2","user_code":"C020552","name":"CART1","details":"[{\"Id\":15480,\"Name2\":\"LISTERINE MOUTHWASH ORIGINAL 500 ML\",\"SalesPriceVM\":460,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=15480\"},{\"Id\":20572,\"Name2\":\"SAVLON ACTIVE HAND WASH RF 1000ML\",\"SalesPriceVM\":230,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=20572\"},{\"Id\":25899,\"Name2\":\"HANDISANITTIZER 200ML SOLUTION\",\"SalesPriceVM\":100,\"DiscountPercentVM\":0,\"product_quantity\":2,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=25899\"}]","created_at":"2020-05-21 01:43:10","updated_at":"2020-05-21 01:43:10"},
{"id":"3","user_code":"C020557","name":"PR 1","details":"[{\"Id\":13319,\"Name2\":\"EXIUM CAPS 20\",\"SalesPriceVM\":8.5,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=13319\"},{\"Id\":16432,\"Name2\":\"DOMIDON 10MG TAB\",\"SalesPriceVM\":2,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=16432\"},{\"Id\":19480,\"Name2\":\"ALOCAP SOFT CAP\",\"SalesPriceVM\":6,\"DiscountPercentVM\":0,\"product_quantity\":10,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=19480\"},{\"Id\":23223,\"Name2\":\"CYNTA 100MG TAB.\",\"SalesPriceVM\":25,\"DiscountPercentVM\":0,\"product_quantity\":40,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=23223\"},{\"Id\":2063,\"Name2\":\"MARLOX PLUS-200 ML-SUSPENSION\",\"SalesPriceVM\":110,\"DiscountPercentVM\":0,\"product_quantity\":1,\"Image_Url\":\"http:\\\/\\\/182.160.118.235:8099\\\/api\\\/ImageFile\\\/GetImage?enumEntityType=2&entityId=2063\"}]","created_at":"2020-05-21 07:30:29","updated_at":"2020-05-21 07:30:29"},
]
}
I am trying to read "details". In details, there are three objects I am trying to read Id,product_quantity of each object and insert them into the db table.
MY Code
public void PostSaveCartItemData()
{
var contents = File.ReadAllText("saved_carts.json");
dynamic jsonResponse = JsonConvert.DeserializeObject(contents);
int i = 0;
using (MainDataContext ctx = new MainDataContext())
{
List<SavedCartItem> list = new List<SavedCartItem>();
foreach (var item in jsonResponse.data)
{
var productId = item.details[i].Id;
var qty = item.details[i].product_quantity;
i++;
SavedCartItem entity = new SavedCartItem()
{
ProductId = productId,
Qty = qty ,
};
list.Add(entity);
}
ctx.SavedCartItems.AddRange(list);
ctx.SaveChanges();
}
}
Your kind help will be highly appreciated.

The details property is JSON encoded as a string, you need to further deserialise that value if you want to use it. Also, you should avoid using dynamic, there's no need. For example:
var jsonResponse = JObject.Parse(Json);
foreach (var item in jsonResponse["data"])
{
var detailsJson = item["details"];
var details = JArray.Parse(detailsJson.ToString());
foreach(var detail in details)
{
var productId = detail["Id"];
var qty = detail["product_quantity"];
Console.WriteLine(productId);
Console.WriteLine(qty);
}
}

Related

How to access specific value from deep within Json output in C# console application

I am accessing the following Json output from a sports statistics API and want to get the specific value that rests in the away team ID for each game being played. (dates>games>teams>away>team:id). Json show here: https://statsapi.web.nhl.com/api/v1/schedule
I've been successful using jObject.Parse() for much of the rest of my project but this value is buried and my knowledge is limited on how to expand my nest to reach it. Any help would be greatly appreciated.
so far I am trying like so but getting errors stating I am accessing invalid key values.
public List<string> GetAwayTeamsPlayingToday()
{
var URL = new UriBuilder("https://statsapi.web.nhl.com/api/v1/schedule");
var client = new WebClient();
List<string> awayTeamsPlayingToday = new List<string>();
JObject ScheduleData = JObject.Parse(client.DownloadString(URL.ToString()));
string lplayerAwayTeamId = string.Empty;
var dates = ScheduleData["dates"] as JArray;
foreach (JObject date in dates)
{
var games = dates["games"] as JArray;
foreach (JObject game in games)
{
var teams = games["teams"] as JArray;
foreach (JObject team in teams)
{
var away = teams["away"] as JArray;
foreach (JObject tm in away)
{
var awayTeam = away["team"] as JObject;
lplayerAwayTeamId = awayTeam["id"].ToString();
awayTeamsPlayingToday.Add(lplayerAwayTeamId);
}
}
}
}
return awayTeamsPlayingToday;
}
You can do this
var URL = new UriBuilder("https://statsapi.web.nhl.com/api/v1/schedule");
var client = new WebClient();
List<string> awayTeamsPlayingToday = new List<string>();
JObject ScheduleData = JObject.Parse(client.DownloadString(URL.ToString()));
var data = JsonConvert.DeserializeObject<dynamic>(ScheduleData.ToString());
//this sample is for first date, first game
var awayTeamId = data.dates[0].games[0].teams.away.team.id;
//to get each game
foreach (var date in data.dates)
{
foreach (var game in date.games)
{
var id = game.teams.away.team.id;
//your logic
}
}

UWP - Compare data on JSON and database

I have a database called ebookstore.db as below:
and JSON as below:
I want when slug on JSON is not the same as a title in the database, it will display the amount of data with a slug on JSON which is not same as a title in the database in ukomikText.
Code:
string judulbuku;
try
{
string urlPath1 = "https://...";
var httpClient1 = new HttpClient(new HttpClientHandler());
httpClient1.DefaultRequestHeaders.TryAddWithoutValidation("KIAT-API-KEY", "....");
var values1 = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("halaman", 1),
new KeyValuePair<string, string>("limit", 100),
};
var response1 = await httpClient1.PostAsync(urlPath1, new FormUrlEncodedContent(values1));
response1.EnsureSuccessStatusCode();
if (!response1.IsSuccessStatusCode)
{
MessageDialog messageDialog = new MessageDialog("Memeriksa update Komik gagal", "Gangguan Server");
await messageDialog.ShowAsync();
}
string jsonText1 = await response1.Content.ReadAsStringAsync();
JsonObject jsonObject1 = JsonObject.Parse(jsonText1);
JsonArray jsonData1 = jsonObject1["data"].GetArray();
foreach (JsonValue groupValue in jsonData1)
{
JsonObject groupObject = groupValue.GetObject();
string id = groupObject["id"].GetString();
string judul = groupObject["judul"].GetString();
string slug = groupObject["slug"].GetString();
BukuUpdate file1 = new BukuUpdate();
file1.ID = id;
file1.Judul = judul;
file1.Slug = slug;
List<String> title = sqlhelp.GetKomikData();
foreach (string juduldb in title)
{
judulbuku = juduldb.Substring(juduldb.IndexOf('.') + 1);
if (judulbuku != file1.Slug.Replace("-", "_") + ".pdf")
{
BukuData.Add(file1);
ListBuku.ItemsSource = BukuData;
}
else
{
ukomikText.Text = "belum tersedia komik yang baru";
ukomikText.Visibility = Visibility.Visible;
}
}
}
if (ListBuku.Items.Count > 0)
{
ukomikText.Text = BukuData.Count + " komik baru";
ukomikText.Visibility = Visibility.Visible;
jumlahbuku = BukuData.Count;
}
else
{
ukomikText.Text = "belum tersedia komik yang baru";
ukomikText.Visibility = Visibility.Visible;
}
public static List<String> GetKomikData()
{
List<String> entries = new List<string>();
using (SqliteConnection db =
new SqliteConnection("Filename=ebookstore.db"))
{
db.Open();
SqliteCommand selectCommand = new SqliteCommand
("SELECT title FROM books where folder_id = 67", db);
SqliteDataReader query = selectCommand.ExecuteReader();
while (query.Read())
{
entries.Add(query.GetString(0));
}
db.Close();
}
return entries;
}
BukuUpdate.cs:
public string ID { get; set; }
public string Judul { get; set; }
public string Slug { get; set; }
I have a problem, that is when checking slugs on JSON, then the slug that is displayed is the first slug is displayed repeatedly as much data in the database, after that show the second slug repeatedly as much data on the database, and so on, as below:
How to solve it so that slug on JSON is not displayed repeatedly (according to the amount of data on JSON)?
The problem is that you have two nested foreach loops. What the code does in simplified pseudocode:
For each item in JSON
Load all rows from DB
And for each loaded row
Check if the current JSON item matches the row from DB and if not, output
As you can see, if you have N items in the JSON and M rows in the database, this inevitably leads to N*M lines of output except for those rare ones where the JSON item matches a specific row in database.
If I understand it correctly, I assume that you instead want to check if there is a row that matches the JSON item and if not, output it. You could do this the following way:
List<String> title = sqlhelp.GetKomikData();
HashSet<string> dbItems = new HashSet<string>();
foreach (string juduldb in title)
{
judulbuku = juduldb.Substring(juduldb.IndexOf('.') + 1);
dbItems.Add( judulbuku );
}
...
foreach ( JsonValue groupValue in jsonData1 )
{
...
//instead of the second foreach
if ( !dbItems.Contains( file1.Slug.Replace("-", "_") + ".pdf" ) )
{
//item is not in database
}
else
{
//item is in database
}
}
Additional tips
Avoid calling GetKomikData inside the foreach. This method does not have any arguments and that means you are just accessing the database again and again without a reason, which takes time and slows down the execution significantly. Instead, call GetKomikData only once before the first foreach and then just use title variable.
Don't assign ItemsSource every time the collection changes. This will unnecessarily slow down the UI thread, as it will have to reload all the items with each loop. Instead, assign the property only once after the outer foreach
write your code in one language. When you start mixing variable names in English with Indonesian, the code becomes confusing and less readable and adds cognitive overhead.
avoid non-descriptive variable names like file1 or jsonObject1. The variable name should be clear and tell you what it contains. When there is a number at the end, it usually means it could be named more clearly.
use plurals for list variable names - instead of title use titles

How can I ensure rows are not loaded twice with EF / LINQ

I created code to load definitions from an external API. The code iterates through a list of words, looks up a definition for each and then I thought to use EF to insert these into my SQL Server database.
However if I run this twice it will load the same definitions the second time. Is there a way that I could make it so that EF does not add the row if it already exists?
public IHttpActionResult LoadDefinitions()
{
var words = db.Words
.AsNoTracking()
.ToList();
foreach (var word in words)
{
HttpResponse<string> response = Unirest.get("https://wordsapiv1.p.mashape.com/words/" + word)
.header("X-Mashape-Key", "xxxx")
.header("Accept", "application/json")
.asJson<string>();
RootObject rootObject = JsonConvert.DeserializeObject<RootObject>(response.Body);
var results = rootObject.results;
foreach (var result in results)
{
var definition = new WordDefinition()
{
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
db.SaveChanges();
}
return Ok();
}
Also would appreciate if anyone has any suggestions as to how I could better implement this loading.
foreach (var result in results)
{
if(!(from d in db.WordDefinitions where d.Definition == result.definition select d).Any())
{
var definition = new WordDefinition()
{
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
}
You can search for Definition value.
var wd = db.WordDefinition.FirstOrDefault(x => x.Definition == result.definition);
if(wd == null) {
var definition = new WordDefinition() {
WordId = word.WordId,
Definition = result.definition
};
db.WordDefinitions.Add(definition);
}
In this way you can get a WordDefinition that already have your value.
If you can also use WordId in the same way:
var wd = db.WordDefinition.FirstOrDefault(x => x.WordId == word.WordId);

How to fetch entity records from CRM

I am very new to MS-CRM and I want to retreive all the details of the contact
var executeQuickFindRequest = new OrganizationRequest("ExecuteQuickFind");
executeQuickFindRequest.Parameters = new ParameterCollection();
var entities = new List<string> { "contact", "lead", "account" }; //specify search term
executeQuickFindRequest.Parameters.Add("SearchText", "maria");
//will cause serialisation exception if we don't convert to array
executeQuickFindRequest.Parameters.Add("EntityNames", entities.ToArray());
var executeQuickFindResponse = _orgService.Execute(executeQuickFindRequest);
var result = executeQuickFindResponse.Results;
The data here displayed contains display name's such as address_1_City,email_user
However I want to get there actual names like Address,Email etc etc.
Thanks
Just to extend what BlueSam has mentioned above.
EntityMetadata entityMetaData = retrieveEntityResponse.EntityMetadata;
for (int count = 0; count < entityMetaData.Attributes.ToList().Count; count++)
{
if (entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels.Count > 0)
{
string displayName = entityMetaData.Attributes.ToList()[count].DisplayName.LocalizedLabels[0].Label;
string logicalName = entityMetaData.Attributes.ToList()[count].LogicalName;
AttributeTypeCode dataType = (AttributeTypeCode)entityMetaData.Attributes.ToList()[count].AttributeType;
}
}
Above code will help you to get the display name, logical name and data type for each attribute in the entity. Similarly you can get other information as well from the entityMetaData object as per above code snippet.
As far as I know, you will need to pair it up with the attributes of the entities that are for that request. Here's a sample of how to retrieve an entity:
RetrieveEntityRequest retrieveBankAccountEntityRequest = new RetrieveEntityRequest
{
EntityFilters = EntityFilters.Entity,
LogicalName = entityName
};
RetrieveEntityResponse retrieveEntityResponse = (RetrieveEntityResponse)_serviceProxy.Execute(retrieveBankAccountEntityRequest);
You can do it easy as below
using (var service = new OrganizationService(CrmConnection.Parse("CRMConnectionString")))
{
var Res = service.Retrieve("sv_answer", new Guid("GUID Of Record"), new ColumnSet("ColumnName "));
}

LINQ EF copy and paste a record with a difference field

i need copy and paste some records of my table with just but change one field.
here is my code:
using (ClearWhiteDBEntities cwContext = new ClearWhiteDBEntities())
{
var qlstfld = from lstflds in cwContext.tblListFields
where lstflds.listId == theLongSrc
select lstflds;
foreach (var item in qlstfld)
{
tblListField lstFldRow = new tblListField
{
name = item.name,
filterFieldId = item.filterFieldId,
listId = theLongDes, //this field must be change in paste
continueById = item.continueById,
destinationId = item.destinationId,
conditionId = item.conditionId,
userId = userId,
date = Convert.ToDateTime(DateTime.Now.ToShortDateString()),
time = DateTime.Now.TimeOfDay,
IP = trueIp
};
cwContext.AddTotblListFields(lstFldRow);
cwContext.SaveChanges();
}
}
but i get this error:
an error accured white starting a transaction on the provider connection. see the inner exception for details.
what is best solution to copy and paste records but change one field?
If you are using change tracking:
using (ClearWhiteDBEntities cwContext = new ClearWhiteDBEntities())
{
var qlstfld = from lstflds in cwContext.tblListFields
where lstflds.listId == theLongSrc
select lstflds;
foreach (var item in qlstfld)
{
cwContext.ObjectStateManager.ChangeObjectState(item, System.Data.EntityState.Added);
item.Id = 0;
item.listId = theLongDes; //this field must be change in paste
}
cwContext.SaveChanges();
}

Categories

Resources