Eager loading only appear in some result - .net-core

I am currently using .Net Core 3.0 and I'm building a Web API.
I am trying to eager load some related data to the frontend.
I have the following classes and dbcontext setup.
public class EntityCommon
{
public int Id { get; set; }
public DateTime CreatedDatetime { get; set; }
}
public class UserAmountClaim: EntityCommon
{
public int UserId { get; set; }
public AmountClaimType Type { get; set; }
public int Amount{ get; set; }
public int? RefereeId { get; set; }
public AmountClaimStatus Status { get; set; }
public DateTime? ClaimedDatetime { get; set; }
[NotMapped]
public virtual User Referee { get; set; }
}
public class User : EntityCommon
{
public string Name { get; set; }
public string Password { get; set; }
public UserStatus Status { get; set; }
[NotMapped]
public virtual UserAmountClaim UserAmountClaim { get; set; }
}
DbContext
modelbuilder.Entity<UserAmountClaim>().ToTable("UserAmountClaim ", "dbo");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.UserId).HasColumnName("fkUserId");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.RefereeId).HasColumnName("fkRefereeId");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.Type).HasConversion(new EnumToStringConverter<UserAmountClaim>());
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.CreatedDatetime).ValueGeneratedOnAdd();
modelbuilder.Entity<UserAmountClaim>().HasOne(ucc => ucc.Referee).WithOne(user => user.UserAmountClaim);
Startup.cs
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
options.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-ddTHH:mm:ss" });
options.SerializerSettings.Converters.Add(new StringEnumConverter());
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
});
And also data such as below
Id fkUserId Type Amount fkRefereeId Status ClaimedDateTime CreatedDatetime
52 1 ReferralCommission 100 2 6 NULL 2020-04-18 15:19:34.203
53 1 ReferralCommission 100 2 6 NULL 2020-04-18 15:19:40.343
54 1 ReferralCommission 100 1 6 NULL 2020-04-18 15:36:44.017
55 1 ReferralCommission 100 1 6 NULL 2020-04-18 15:51:31.757
But when i execute the following code
var result = _dbContext.UserAmountClaim.Where(x => x.UserId == userId &&
x.Status == AmountClaimStatus.PendingUser &&
x.Type == AmountClaimType.ReferralCommission)
.Include(x => x.Referee)
.ToListAsync();
The referee is missing in the first and third item
{
"userId": 1,
"type": "ReferralCommission",
"amount": 100,
"status": "PendingUser",
"id": 52,
"createdDatetime": "2020-04-18T15:19:34"
},
{
"userId": 1,
"type": "ReferralCommission",
"amount": 100,
"refereeId": 2,
"status": "PendingUser",
"referee": {
"id": 2,
"name": "82109380918",
"password": "",
"status": "Valid",
"createdDatetime": "2020-04-16T17:45:31",
},
"id": 53,
"createdDatetime": "2020-04-18T15:19:40"
},
{
"userId": 1,
"type": "ReferralCommission",
"credit": 100,
"status": "PendingUser",
"id": 54,
"createdDatetime": "2020-04-18T15:36:44"
},
{
"userId": 1,
"type": "ReferralCommission",
"amount": 100,
"refereeId": 1,
"status": "PendingUser",
"referee": {
"id": 1,
"name": "31829389031",
"password": "",
"status": "Valid",
"createdDatetime": "2020-04-16T17:45:31",
},
"id": 54,
"createdDatetime": "2020-04-18T15:36:44"
}
This is happening all over other places that has the similar structure.
Anyone can enlighten me what's causing this and how to solve this ?

As pointed out by #IvanStoev, it was a mistaken in setting up the relationship and property class
Modifying following works for me.
public class User : EntityCommon
{
public string Name { get; set; }
public string Password { get; set; }
public UserStatus Status { get; set; }
[NotMapped]
public virtual List<UserAmountClaim> UserAmountClaim { get; set; }
}
DbContext
modelbuilder.Entity<UserAmountClaim>().ToTable("UserAmountClaim ", "dbo");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.UserId).HasColumnName("fkUserId");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.RefereeId).HasColumnName("fkRefereeId");
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.Type).HasConversion(new EnumToStringConverter<UserAmountClaim>());
modelbuilder.Entity<UserAmountClaim>().Property(ucc => ucc.CreatedDatetime).ValueGeneratedOnAdd();
modelbuilder.Entity<UserAmountClaim>().HasOne(ucc => ucc.Referee).WithMany(user => user.UserAmountClaim);
Big thanks to #IvanStoev

Related

How to show recursive list from coming api in .net core

I have function like this and this function get all subfolders. My Folder Model:
public partial class Folder
{
public Folder()
{
Files = new HashSet<File>();
InverseParentFolder = new HashSet<Folder>();
}
[Key]
public int Id { get; set; }
[Required]
[StringLength(50)]
public string FolderName { get; set; }
public Guid FileGuid { get; set; }
public int Size { get; set; }
public int? ParentFolderId { get; set; }
public int AppUserId { get; set; }
public bool IsDeleted { get; set; }
[Column(TypeName = "datetime")]
public DateTime CreatedAt { get; set; }
[ForeignKey(nameof(AppUserId))]
[InverseProperty(nameof(User.Folders))]
public virtual User AppUser { get; set; }
[ForeignKey(nameof(ParentFolderId))]
[InverseProperty(nameof(Folder.InverseParentFolder))]
public virtual Folder ParentFolder { get; set; }
[InverseProperty(nameof(File.Folder))]
public virtual ICollection<File> Files { get; set; }
[InverseProperty(nameof(Folder.ParentFolder))]
public virtual ICollection<Folder> InverseParentFolder { get; set; }
}
And my function :
public async Task<List<Folder>> GetAllSubFolders(int folderId)
{
List<Folder> result = new List<Folder>();
await GetFolders(folderId, result);
return result;
}
//Recursive function that take all subfolders inside of one folder.
private async Task GetFolders(int folderId, ICollection<Folder> result)
{
using var context = new FilemanagementContext();
var folders =await context.Folders.Where(I => I.ParentFolderId== folderId && I.IsDeleted==false).ToListAsync();
if (folders.Count >0)
{
foreach (var folder in folders)
{
if (folder.InverseParentFolder==null)
folder.InverseParentFolder = new List<Folder>();
await GetFolders(folder.Id, folder.InverseParentFolder);
if (!result.Contains(folder))
{
result.Add(folder);
}
}
}
}
Simple response message :
{
"id": 3,
"folderName": "Child Edited Name",
"fileGuid": "d056e29b-2034-4ecc-a12e-e79d5d2ce494",
"size": 148,
"parentFolderId": 2,
"appUserId": 2,
"isDeleted": false,
"createdAt": "2021-03-02T11:22:52.653",
"appUser": null,
"parentFolder": null,
"files": [],
"inverseParentFolder": [
{
"id": 6,
"folderName": "Child Folder 3",
"fileGuid": "3d559aa8-0216-4498-9de2-896d51110773",
"size": 0,
"parentFolderId": 3,
"appUserId": 2,
"isDeleted": false,
"createdAt": "2021-03-03T13:17:27.523",
"appUser": null,
"parentFolder": null,
"files": [],
"inverseParentFolder": []
}
]
}
I will zip this parent and child folders from coming information above. I can already zip some folders and files also i will zip folders on controller.
So my question is how do I zip the folders coming from this recursive function one by one?

LINQ query to select inner list only(Issue in JSON response)

I am facing issue in LINQ query, basically, it not returning records as per required format of JSON. I have two entity Users and And Address both have foreign key relation.
I have 2 entity as below
public class Users
{
public int Id { set; get; }
public string FName { set; get; }
public string LName { set; get; }
public string UserName { set; get; }
public string Password { set; get; }
public ICollection<Address> Address{ set; get; }
public string Contact { set; get; }
public decimal Salary { set; get; }
public string xyz { set; get; }
}
public class Address
{
public int AddressID { set; get; }
public string Address1 { set; get; }
public string Address2 { set; get; }
public string City { set; get; }
}
Context Class
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options): base(options)
{
}
public DbSet<Users> Users { get; set; }
}
API
[HttpGet("getaddressbyuser/{userId}")]
[Route("getaddressbyuser")]
public async Task<ActionResult<List<ICollection<Address>>>> GetAddressByUser(int userId)
{
var addr = await _context.Users.Where(x => x.Id == userId).Select(y => y.Address).ToListAsync();
if (addr == null)
{
return NotFound();
}
return addr;
}
When I called the API
http://localhost:55433/api/Users/getaddressbyuser/2
It' returns the following json
[
[
{
"addressID": 1,
"address1": "Noida",
"address2": "Noida 201301",
"city": "Noida"
},
{
"addressID": 2,
"address1": "Noida",
"address2": "Noida 201301",
"city": "Noida"
}
]
]
While I wnat to records as below
[
{
"addressID": 1,
"address1": "Noida",
"address2": "Noida 201301",
"city": "Noida"
},
{
"addressID": 2,
"address1": "Noida",
"address2": "Noida 201301",
"city": "Noida"
}
]
Note: I am using DotNet Core 2.2, Thanks
var addr = await _context.Users.Where(x => x.Id == userId).SelectMany(y=>y.Address).ToListAsync();
The problem is with select. Address is a list thus you need to use select many to flatten the results. In your select statement you tell him from a list of users select for each user their adresses so you have a list of users where each user has a list of addresses. So the it's not JSON problem or anything. If you use debuggger you will see that in C# it's a list containing lists. Plus considering that you want this JSON your return type is incorrect. Simply use IEnumarable<Address>
Change your return type.
Try with type <List<Address>>
If you want to use ICollection you can use only ICollection<Address>

How to deserialize nested JSON and tied it to model to represent in view

I am calling RestApi which is giving me Nested JSON in response. I have to handle this nested Json and represent on same Partial View. I will share my model , view and controller code.
I created controller to call api and collect data. Its populating root class but not populating child class
JSON:
{
"id": 98,
"title": "all numbers",
"clues_count": 5,
"clues": [
{
"id": 602,
"answer": "<i>Eight</i>",
"question": "It was \"enough\" for Dick van Patten",
"value": 100,
"airdate": "1984-09-14T12:00:00.000Z",
"category_id": 98,
"game_id": null,
"invalid_count": null
},
{
"id": 608,
"answer": "16",
"question": "A teen's \"sweet\" age",
"value": 200,
"airdate": "1984-09-14T12:00:00.000Z",
"category_id": 98,
"game_id": null,
"invalid_count": null
},
{
"id": 614,
"answer": "<i>The Grapes of Wrath</i>",
"question": "",
"value": null,
"airdate": "1984-09-14T12:00:00.000Z",
"category_id": 98,
"game_id": null,
"invalid_count": null
},
{
"id": 620,
"answer": "Nathaniel Hawthorne",
"question": "",
"value": null,
"airdate": "1984-09-14T12:00:00.000Z",
"category_id": 98,
"game_id": null,
"invalid_count": null
},
{
"id": 626,
"answer": "F. Scott Fitzgerald",
"question": "",
"value": null,
"airdate": "1984-09-14T12:00:00.000Z",
"category_id": 98,
"game_id": null,
"invalid_count": 1
}
]
}
Model:
public class Clue
{
public int id { get; set; }
public string answer { get; set; }
public string question { get; set; }
public int? value { get; set; }
public DateTime airdate { get; set; }
public int category_id { get; set; }
public object game_id { get; set; }
public int? invalid_count { get; set; }
}
public class RootObject
{
public int id { get; set; }
public string title { get; set; }
public int clues_count { get; set; }
public List<Clue> clues { get; set; }
}
Controller
public async Task<ActionResult> Category( int id)
{
// List<Category> clueInfo = new List<Category>();
List<RootObject> cluess = new List<RootObject>();
RootObject category = new RootObject();
category.clueslist = new List<Clues>();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("api/category?id=" + id);
Debug.WriteLine("My debug string here");
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var ClueResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
category = JsonConvert.DeserializeObject<RootObject>(ClueResponse);
}
// return View();
return PartialView("Category", cluess);
}
Result on view
title
clues_count
dining out
20

JSON.NET error "Cannot deserialize the current JSON array (e.g. [1,2,3]) into type because the type requires a JSON object (e.g. {"name":"value"})"

I have the following WebCleint to call a Restful web service inside my .net console application:-
try
{
using (WebClient wc = new WebClient())
{
wc.Encoding = Encoding.UTF8;
string url = "https://*****/paged?hapikey=*********&properties=website&properties=i_scan&limit=2";//web service url
string tempurl = url.Trim();
var json = wc.DownloadString(tempurl);//get the json
Marketing ipfd = JsonConvert.DeserializeObject<Marketing>(json);//deserialize
}
}
catch (Exception e)
{
//code goes here..
}
where i am using JSON.Net to Deserialize the json object, which will be as follow:-
{
"has-more": true,
"offset": 622438650,
"companies": [
{
"portalId": *******,
"companyId": *****,
"isDeleted": false,
"properties": {
"website": {
"value": "****.net",
"timestamp": 1520938239457,
"source": "CALCULATED",
"sourceId": null,
"versions": [
{
"name": "website",
"value": "*****.net",
"timestamp": 1520938239457,
"source": "CALCULATED",
"sourceVid": [
731938234
]
}
]
}
},
"additionalDomains": [],
"stateChanges": [],
"mergeAudits": []
},
{
"portalId": ******,
"companyId": ******,
"isDeleted": false,
"properties": {
"website": {
"value": "****.***.***",
"timestamp": 1512488590073,
"source": "CALCULATED",
"sourceId": null,
"versions": [
{
"name": "website",
"value": "****.***8.****",
"timestamp": 1512488590073,
"source": "CALCULATED",
"sourceVid": []
}
]
},
"i_scan": {
"value": "Yes",
"timestamp": 1543409493459,
"source": "******",
"sourceId": "**************",
"versions": [
{
"name": "i_scan",
"value": "Yes",
"timestamp": 1543409493459,
"sourceId": *****",
"source": "CRM_UI",
"sourceVid": [],
"requestId": "******"
}
]
}
},
"additionalDomains": [],
"stateChanges": [],
"mergeAudits": []
}
]
}
Here are my classes:-
public class Marketing
{
public Companies companies { get; set; }
}
public class Companies
{
public IList<string> companyId { get; set; }
public IList<Properties> properties { get; set; }
}
public class Properties
{
public IList<Website> website { get; set; }
public IList<I_Scan> i_scan { get; set; }
}
public class Website
{
public string value { get; set; }
}
public class i_Scan
{
public string value { get; set; }
}
but currently i am getting this exception, when i try to de-serialize the JSON object:-
Newtonsoft.Json.JsonSerializationException was caught
HResult=-2146233088
Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'MMarketing.Companies' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path 'companies', line 1, position 49.
Source=Newtonsoft.Json
StackTrace:
so i am not sure why JSON.NET is unable to do the Deserialize correctly, as in my case the classes are compatible with the returned json object??
At a first glance it looks like you switched two properties in Making them a List and vice versa.
public class Marketing
{
public List<Companies> companies { get; set; }
}
Is "companies": [ in the json, while "companyId": *****, is the id as a string, not array. Properties is not an array also, but the property versions of properties is.
public class Companies
{
public string companyId { get; set; }
public Properties properties { get; set; }
}
If I'm coming to json blind I like to use http://json2csharp.com/ to generate my class structure for me
public class Version
{
public string name { get; set; }
public string value { get; set; }
public object timestamp { get; set; }
public string source { get; set; }
public List<object> sourceVid { get; set; }
}
public class Website
{
public string value { get; set; }
public object timestamp { get; set; }
public string source { get; set; }
public object sourceId { get; set; }
public List<Version> versions { get; set; }
}
public class Version2
{
public string name { get; set; }
public string value { get; set; }
public long timestamp { get; set; }
public int sourceId { get; set; }
public string source { get; set; }
public List<object> sourceVid { get; set; }
public int requestId { get; set; }
}
public class IScan
{
public string value { get; set; }
public long timestamp { get; set; }
public int source { get; set; }
public int sourceId { get; set; }
public List<Version2> versions { get; set; }
}
public class Properties
{
public Website website { get; set; }
public IScan i_scan { get; set; }
}
public class Company
{
public int portalId { get; set; }
public int companyId { get; set; }
public bool isDeleted { get; set; }
public Properties properties { get; set; }
public List<object> additionalDomains { get; set; }
public List<object> stateChanges { get; set; }
public List<object> mergeAudits { get; set; }
}
public class Marketing
{
public bool has_more { get; set; }
public int offset { get; set; }
public List<Company> companies { get; set; }
}
var result = JsonConvert.DeserializeObject<Marketing>(json);

Deserializing JSON to a .NET object puts null in each member of my object, why?

I am using JSON.NET (Newtonsoft.Json) to deserialize my JSON into a .NET object - here's my JSON string:
{
"SafetyReport": {
"SafetyData": [{
"Unsafe": "YES",
"CategoryName": "Body Mechanics",
"CategoryData": "Grip / Force",
"Safe": "NO"
}, {
"Unsafe": "YES",
"CategoryName": "Position of People",
"CategoryData": "Falling",
"Safe": "NO"
}, {
"Unsafe": "YES",
"CategoryName": "Position of People",
"CategoryData": "Other",
"Safe": "YES"
}],
"SafeActsObserved": "APPLE",
"UnsafeActsObserved": "OK",
"Date": "11 / 11 / 1988",
"ObserverName": "Bob",
"ObserverGroup": "TEST",
"LocationAreaRegion": "Nowhere",
"Email": "abc#abc.com"
}
}
Here's my C# code - please note that the jsonData string contains exactly the JSON above, just in a single line. I've already verified this:
Once I step past the deserialization, here's what's in my SafetyReport object:
Finally, here are my class definitions for SafetyReport and SafetyData:
public class SafetyReport
{
IList<SafetyData> SafetyData { get; set; }
string SafeActsObserved { get; set; }
string UnsafeActsObserved { get; set; }
string Date { get; set; }
string ObserverName { get; set; }
string ObserverGroup { get; set; }
string LocationAreaRegion { get; set; }
string Email { get; set; }
}
public class SafetyData
{
string Unsafe { get; set; }
string Safe { get; set; }
string CategoryName { get; set; }
string CategoryData { get; set; }
}
QUESTION: What am I doing wrong?
Ok I got it working, multiple things might have been wrong, here's what I did:
Added public modifier to every field.
Removed Safetyreport from JSON
Changed all doublequotes(") to quotes (')
Try this:
class Program
{
static void Main(string[] args)
{
string json = #"{
'SafetyData': [{
'Unsafe': 'YES',
'CategoryName': 'Body Mechanics',
'CategoryData': 'Grip / Force',
'Safe': 'NO'
}, {
'Unsafe': 'YES',
'CategoryName': 'Position of People',
'CategoryData': 'Falling',
'Safe': 'NO'
}, {
'Unsafe': 'YES',
'CategoryName': 'Position of People',
'CategoryData': 'Other',
'Safe': 'YES'
}],
'SafeActsObserved': 'APPLE',
'UnsafeActsObserved': 'OK',
'Date': '11 / 11 / 1988',
'ObserverName': 'Bob',
'ObserverGroup': 'TEST',
'LocationAreaRegion': 'Nowhere',
'Email': 'abc#abc.com'
}
";
SafetyReport sr = JsonConvert.DeserializeObject<SafetyReport>(json);
Console.ReadLine();
}
}
public class SafetyReport
{
public IList<SafetyData> SafetyData { get; set; }
public string SafeActsObserved { get; set; }
public string UnsafeActsObserved { get; set; }
public string Date { get; set; }
public string ObserverName { get; set; }
public string ObserverGroup { get; set; }
public string LocationAreaRegion { get; set; }
public string Email { get; set; }
}
public class SafetyData
{
public string Unsafe { get; set; }
public string Safe { get; set; }
public string CategoryName { get; set; }
public string CategoryData { get; set; }
}
Maybe the problem is the first field of the JSON, you haven't to set witch class you will deserialize, you have to set the attribute names to identify them. Try with this json.
{
"SafetyData": [{
"Unsafe": "YES",
"CategoryName": "Body Mechanics",
"CategoryData": "Grip / Force",
"Safe": "NO"
}, {
"Unsafe": "YES",
"CategoryName": "Position of People",
"CategoryData": "Falling",
"Safe": "NO"
}, {
"Unsafe": "YES",
"CategoryName": "Position of People",
"CategoryData": "Other",
"Safe": "YES"
}],
"SafeActsObserved": "APPLE",
"UnsafeActsObserved": "OK",
"Date": "11 / 11 / 1988",
"ObserverName": "Bob",
"ObserverGroup": "TEST",
"LocationAreaRegion": "Nowhere",
"Email": "abc#abc.com"
}
Hope it helps.

Resources