How to read property names on related list - c#

With these models:
public class Course
{
public Guid Id { get; set; }
public string Title { get; set; }
public IList<CourseEvent> CourseEvents { get; set; }
}
public class CourseEvent
{
public Guid Id { get; set; }
public Guid CourseId { get; set; }
public DateTime StartDate { get; set; }
}
...and this method:
private void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
...I can get the property names and values on any object provided:
var course = new Course { Title = "My course", CourseEvents = new List<CourseEvent>() { new() { StartDate = DateTime.Today }, new() { StartDate = DateTime.Today.AddDays(-1) } } };
WritePropertyNames(course);
But how do I get the related CourseEvents property names and values too? I've tried this, but that's not right:
foreach (var item2 in obj.GetType().GetProperty("CourseEvents").GetType().GetProperties())
{
Console.WriteLine(item2.Name + " => " + item2.GetValue(obj, null));
}

It might be ugly and not optimal and won't work for all the cases (quickly wrote it just to demonstrate the idea)
So you could check if property is Generic by item.PropertyType.IsGenericType, you could also check if it type implements IEnumerable typeof(IEnumerable).IsAssignableFrom(item.PropertyType). Then you could get the underlying type using item.PropertyType.GenericTypeArguments[0]. Then it basically becomes your logic that you have - you iterating over objects and getting props as you already have
private static void WritePropertyNames(object obj)
{
foreach (var item in obj.GetType().GetProperties())
{
if(item.PropertyType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(item.PropertyType))
{
var innerProps = item.PropertyType.GenericTypeArguments[0].GetProperties();
foreach(var innerItem in item.GetValue(obj, null) as IEnumerable)
{
foreach(var innerProp in innerProps)
{
Console.WriteLine(item.Name + " => " + innerProp.Name + " => " + innerProp.GetValue(innerItem, null));
}
}
}
else
{
Console.WriteLine(item.Name + " => " + item.GetValue(obj, null));
}
}
}

Related

Dynamic LINQ Query System.Linq.Dynamic.Core

System.Linq.Dynamic.Core.Exceptions.ParseException: 'No property or field 'Name' exists in type 'IEnumerable`1''
How to use Complex object to do order by in Dynamic linq query! I am using System.Linq.Dynamic.Core for dynamic linq query.
public class Course
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Student> Students { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public Course Course { get; set; }
}
using (var context = new SchoolContext())
{
var list = context.Courses.Include("Students").AsQueryable();
var result = list.OrderBy("Students.Name").ToList();
foreach (var item in list)
{
Console.WriteLine("Hello World!" + item.Name );
}
}
The issue you are running into is trying to run an order by on a list.
If you want the students ordered by name in a course try the following
var list = context.Courses.Include(c => c.Students).AsQueryable();
var result = list.Select(course =>
new Course {
Id = course.Id,
Name = course.Name,
Students = course.Students.OrderBy(s => s.Name)
}).ToList();
foreach (var item in list)
{
foreach(var student in item.Students)
{
Console.WriteLine("Hello World!" + student.Name );
}
}

C# retrieve parent-child url from full url using recursively

I need your help in getting parent-child URL list from full URL, maybe using recursively.
For example, below is URL in flat structure. I have to parse in parent-child form with inner level of child structure.
https://domain/UrlA/UrlA_L1/UrlA_L1_L2
https://domain/UrlA/UrlA_L1/UrlA2_L1_L2
https://domain/UrlB/UrlB_L1/UrlB_L1_L2
https://domain/UrlC/UrlC_L1/UrlC_L1_L2
https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3
https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3
https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3
into a list of URL with child-parent relationship.
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
public List<HtmlSiteMap> Childrens { get; set; }
}
my expected output
{
Url: https://domain/UrlA,
PageTitle : UrlA,
UrlLevel : 0 ,
Childrens : {
Url : https://domain/UrlA/UrlA_L1,
PageTitle : UrlA_L1,
UrlLevel : 1,
Childrens : {
Url : https://domain/UrlA/UrlA_L1/UrlA_L1_L2,
PageTitle : UrlA_L1_L2,
UrlLevel : 2,
Childrens : null
},
{
Url : https://domain/UrlA/UrlA_L1/UrlA2_L1_L2,
PageTitle : UrlA2_L1_L2,
UrlLevel : 2,
Childrens : null
}
},
Url: https://domain/UrlB,
PageTitle : UrlB,
UrlLevel : 0 ,
Childrens : {
Url : https://domain/UrlB/UrlB_L1,
PageTitle : UrlB_L1,
UrlLevel : 1,
Childrens : {
Url : https://domain/UrlB/UrlB_L1/UrlB_L1_L2,
PageTitle : UrlB_L1_L2,
UrlLevel : 2,
Childrens : null
}
}
.................
.................
..................
}
I have tried to achieve by splitting and recursively. But unable to get a result. Your help will be appreciated.
Here is another reverse solution. I am working on preordered list, constructing nodes from roots to leaves. This code looks more readable and understandable by beginners in recursion.
static void Main(string[] args)
{
var input = new[]
{
new Uri("https://domain/UrlA/UrlA_L1/UrlA_L1_L2"),
new Uri("https://domain/UrlA/UrlA_L1/UrlA2_L1_L2"),
new Uri("https://domain/UrlB/UrlB_L1/UrlB_L1_L2"),
new Uri("https://domain/UrlC/UrlC_L1/UrlC_L1_L2"),
new Uri("https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3"),
new Uri("https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3"),
new Uri("https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3")
};
var rows = input.Select(u => u.AbsolutePath.Substring(1))
.OrderBy(s => s).Select(s => s.Split('/')).ToList();
var rootNodes = new List<HtmlSiteMap>();
ProcessNodes(rootNodes, rows,
input.Select(u => $"{u.Scheme}://{u.Host}/").Distinct().FirstOrDefault(), 0);
foreach (var node in rootNodes)
Console.WriteLine(node.ToString());
}
static void ProcessNodes(List<HtmlSiteMap> children, List<string[]> rows, string prefix, int level)
{
if (rows.Count == 0)
return;
HtmlSiteMap currentNode = null;
var subRows = new List<string[]>();
foreach (var parts in rows)
{
if (parts.Length == 0)
continue;
subRows.Add(parts.Skip(1).ToArray());
if (currentNode != null && currentNode.PageTitle == parts[0])
continue;
if(currentNode != null)
ProcessNodes(currentNode.Children, subRows, prefix + currentNode.PageTitle + "/", level + 1);
currentNode = new HtmlSiteMap
{
Url = prefix + parts[0],
PageTitle = parts[0],
UrlLevel = level
};
children.Add(currentNode);
subRows.Clear();
}
if(currentNode != null && subRows.Count > 0)
ProcessNodes(currentNode.Children, subRows, prefix + currentNode.PageTitle + "/", level + 1);
}
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
//Also renamed this from Childrens to Children
public List<HtmlSiteMap> Children { get; set; }
public HtmlSiteMap()
{
Children = new List<HtmlSiteMap>();
}
//Borrowed this from previous answer
public override string ToString()
{
var shift = new string(' ', UrlLevel);
var sb = new StringBuilder();
sb.AppendLine(shift + $"Url: {Url},");
sb.AppendLine(shift + $"PageTitle: {PageTitle},");
sb.AppendLine(shift + $"UrlLevel: {UrlLevel},");
sb.AppendLine(shift + "Children:");
if (Children.Count == 0)
{
sb.AppendLine(shift + "-");
}
else
{
foreach (var child in Children)
{
sb.AppendLine(child.ToString());
}
}
return sb.ToString();
}
}
A base version (without errors handling) may look like this:
static void Main(string[] args)
{
var input = new List<string>
{
"https://domain/UrlA/",
"https://domain/UrlA/UrlA_L1/",
"https://domain/UrlA/UrlA_L1/UrlA_L1_L2",
"https://domain/UrlA/UrlA_L1/UrlA2_L1_L2",
"https://domain/UrlB",
"https://domain/UrlB/UrlB_L1",
"https://domain/UrlB/UrlB_L1/UrlB_L1_L2",
"https://domain/UrlC/UrlC_L1/UrlC_L1_L2",
"https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3",
"https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3",
"https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3"
};
var output = new List<HtmlSiteMap>();
foreach (var url in input)
{
var parts = url.Split(#"/", StringSplitOptions.RemoveEmptyEntries);
var current = new HtmlSiteMap
{
Url = url,
PageTitle = parts[^1]
};
var parentName = parts[^2];
static HtmlSiteMap FindParent(List<HtmlSiteMap> score, string name)
{
foreach (var item in score)
{
if (item.PageTitle == name)
{
return item;
}
var inChild = FindParent(item.Childrens, name);
if (inChild != null)
{
return inChild;
}
}
return null;
}
var parent = FindParent(output, parentName);
if (parent == null)
{
current.UrlLevel = 1;
output.Add(current);
}
else
{
current.UrlLevel = parent.UrlLevel + 1;
parent.Childrens.Add(current);
}
}
foreach (var current in output)
{
Console.WriteLine(current.ToString());
}
Console.ReadLine();
}
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
public List<HtmlSiteMap> Children { get; set; }
public HtmlSiteMap()
{
Children = new List<HtmlSiteMap>();
}
public override string ToString()
{
var shift = new string(' ', UrlLevel);
var sb = new StringBuilder();
sb.AppendLine(shift + $"Url: {Url},");
sb.AppendLine(shift + $"PageTitle: {PageTitle},");
sb.AppendLine(shift + $"UrlLevel: {UrlLevel},");
sb.AppendLine(shift + "Children:");
if (Children.Count == 0)
{
sb.AppendLine(shift + "-");
}
else
{
foreach (var child in Children)
{
sb.AppendLine(child.ToString());
}
}
return sb.ToString();
}
}

Nested JSON Array C#

I am trying to deserialize a JSON array that has an additional nested object.
Here is a sample C# code. It returns data until it gets to the second array. I know it needs a second foreach loop but I can't seem to get it to work. Any help would be greatly appreciated. Thank you.
string sJSON = #" [{""dateNumeric"":1216000000,""hourOfDay"":0,""customerNumber"":12,""storedepartment"":[{""department"":333,""descriptionOfDepartment"":""Department A""},{""department"":111,""descriptionOfDepartment"":""Department B""}]},{""dateNumeric"":1216000000,""hourOfDay"":3,""customerNumber"":3,""storedepartment"":[{""department"":999,""descriptionOfDepartment"":""Department X""},{""department"":888,""descriptionOfDepartment"":""Department Y""}]}]";
JArray a = JArray.Parse(sJSON);
foreach (JObject o in a.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
string name = p.Name;
string value = (string)p.Value;
Console.WriteLine(name + "-- " + value);
}
}
You can use Newtonsoft.json library for serializing/deserializing the data, as per your requirement kindly follow below code :
First you need to create the class which will capture the data in specified format(as per your data requirement) :
public class RootObject
{
public int dateNumeric { get; set; }
public int hourOfDay { get; set; }
public int customerNumber { get; set; }
public List<Storedepartment> storedepartment { get; set; }
}
public class Storedepartment
{
public int department { get; set; }
public string descriptionOfDepartment { get; set; }
}
Now , for deserialising the Json data use below statement :
string sJSON = #" [{""dateNumeric"":1216000000,""hourOfDay"":0,""customerNumber"":12,""storedepartment"":[{""department"":333,""descriptionOfDepartment"":""Department A""},{""department"":111,""descriptionOfDepartment"":""Department B""}]},{""dateNumeric"":1216000000,""hourOfDay"":3,""customerNumber"":3,""storedepartment"":[{""department"":999,""descriptionOfDepartment"":""Department X""},{""department"":888,""descriptionOfDepartment"":""Department Y""}]}]";
List<RootObject> Data = JsonConvert.DeserializeObject<List<RootObject>>(sJSON);
Once you get data in your list you can perform your required operation on list
Actually you might be able to properly parse your JSON string if you use the following approach.
public static void ProcessJObject(JProperty obj)
{
string name = obj.Name;
string value = "";
if (obj.Value.Type == JTokenType.Array)
{
Console.WriteLine("Array: " + name);
ProcessJArray((JArray)obj.Value);
}
else
{
value = (string)obj.Value;
Console.WriteLine(name + "-- " + value);
}
}
public static void ProcessJArray(JArray arr)
{
foreach (JObject o in arr.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
ProcessJObject(p);
}
}
}
static void Main(string[] args)
{
string sJSON = #" [{""dateNumeric"":1216000000,""hourOfDay"":0,""customerNumber"":12,""storedepartment"":[{""department"":333,""descriptionOfDepartment"":""Department A""},{""department"":111,""descriptionOfDepartment"":""Department B""}]},{""dateNumeric"":1216000000,""hourOfDay"":3,""customerNumber"":3,""storedepartment"":[{""department"":999,""descriptionOfDepartment"":""Department X""},{""department"":888,""descriptionOfDepartment"":""Department Y""}]}]";
JArray a = JArray.Parse(sJSON);
ProcessJArray(a);
Console.Read();
}
So what have I done here. I simply divided the problem of parsing json in two smaller problems one that is solved by the ProcessJObject function (parsing and printing JProperty) and one that is solved by the ProcessJArray function (looping through the JArray and for each JProperty it contain passing it to ProcessJObject function). So now the parsing problem upto any point of nesting of JSON array is solved by the above approach.
Hope it helps.
static void JsonConvert()
{
string sJSON = #"[{""dateNumeric"":1216000000,""hourOfDay"":0,""customerNumber"":12,""storedepartment"":[{""department"":333,""descriptionOfDepartment"":""Department A""},{""department"":111,""descriptionOfDepartment"":""Department B""}]},{""dateNumeric"":1216000000,""hourOfDay"":3,""customerNumber"":3,""storedepartment"":[{""department"":999,""descriptionOfDepartment"":""Department X""},{""department"":888,""descriptionOfDepartment"":""Department Y""}]}]";
var storeDetail = Newtonsoft.Json.JsonConvert.DeserializeObject<List<StoreDetail>>(sJSON);
//iterate your list here
}
public class StoreDetail
{
[JsonProperty("dateNumeric")]
public string DateNumeric { get; set; }
[JsonProperty("hourOfDay")]
public int HourOfDay { get; set; }
[JsonProperty("customerNumber")]
public int CustomerNumber { get; set; }
[JsonProperty("storedepartment")]
public List<StoreDepartment> StoreDepartment { get; set; }
}
public class StoreDepartment
{
[JsonProperty("department")]
public int Department { get; set; }
[JsonProperty("descriptionOfDepartment")]
public string DescriptionOfDepartment { get; set; }
}
string sJSON = #" [{""dateNumeric"":1216000000,""hourOfDay"":0,""customerNumber"":12,""storedepartment"":[{""department"":333,""descriptionOfDepartment"":""Department A""},{""department"":111,""descriptionOfDepartment"":""Department B""}]},{""dateNumeric"":1216000000,""hourOfDay"":3,""customerNumber"":3,""storedepartment"":[{""department"":999,""descriptionOfDepartment"":""Department X""},{""department"":888,""descriptionOfDepartment"":""Department Y""}]}]";
object dJson = Newtonsoft.Json.JsonConvert.DeserializeObject<JArray>(sJSON);
Console.WriteLine(dJson.ToString());
JArray a = JArray.Parse(sJSON);
foreach (JObject o in a.Children<JObject>())
{
foreach (JProperty p in o.Properties())
{
if (p.First.Count() == 0)
{
string name = p.Name;
string value = (string)p.Value;
Console.WriteLine(name + "-- " + value);
}
else
{
string name = p.Name;
Console.WriteLine(name);
string subStr = p.Value.ToString();
JArray aSub = JArray.Parse(subStr);
foreach (JObject oSub in aSub.Children<JObject>())
{
foreach (JProperty pSub in oSub.Properties())
{
string nameSub = pSub.Name;
string valueSub = (string)pSub.Value;
Console.WriteLine("\t" + nameSub + "-- " + valueSub);
}
}
}
}
}
Console.ReadLine();

Nested foreach for self referencing table

i am struggling to find a different approach for this code.
I want to create a dropdown list to select a category.
As you can see it is not clean and does not work for multiple levels.
I am not an expert in .NET and would like to learn how a professional does this.
List<SelectListItem> list = new List<SelectListItem>();
foreach (Category item in db.CategorySet.Where(x => x.ParentCategory == null))
{
list.Add(new SelectListItem { Value = item.Id.ToString(), Text = item.Name });
foreach (Category subitem in item.SubCategories)
{
list.Add(new SelectListItem { Value = subitem.Id.ToString(), Text = " - " + subitem.Name });
foreach (Category subsubitem in subitem.SubCategories)
{
list.Add(new SelectListItem { Value = subsubitem.Id.ToString(), Text = " - - " + subsubitem.Name });
foreach (Category subsubsubitem in subsubitem.SubCategories)
{
list.Add(new SelectListItem { Value = subsubsubitem.Id.ToString(), Text = " - - - " + subsubsubitem.Name });
//...
}
}
}
}
public partial class Category
{
public Category()
{
this.Products = new HashSet<Product>();
this.SubCategories = new HashSet<Category>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Icon { get; set; }
public Nullable<int> ParentCategoryId { get; set; }
public virtual ICollection<Product> Products { get; set; }
public virtual ICollection<Category> SubCategories { get; set; }
public virtual Category ParentCategory { get; set; }
}
Thank you in advance...
Seems like you are making hierarchial tree (using the "-", "- -", and so on).
Assuming your Categories is non-cyclic, you should consider using recursive function to solve your issue, passing your list as well as your printed prefix (the "-") or your "depth" on the recursive search.
Something like below would probably serve:
public void addCatToList(List<SelectedItemList> list, int depth, IEnumerable<Category> cats){
foreach (Category item in cats)
{
list.Add(new SelectListItem { Value = item .Id.ToString(), Text = printDash(depth) + item.Name });
addCatToList(list, depth + 1, item.SubCategories);
}
}
private string printDash(int number){
string dash = string.Empty;
for(int i = 0; i < number; ++i){
if (i == 0)
dash += " ";
dash += "- ";
}
return dash;
}
And then you call it the first time with depth = 0:
List<SelectListItem> list = new List<SelectListItem>();
addCatToList(list, 0, db.CategorySet.Where(x => x.ParentCategory == null));

Accessing Data sets from Json

I am mapping JSON data to my own classes in C# and then trying to display various data where I need it however I'm having a small issue where I can't seem to get at data when I believe I should be able to. Obviously something is wrong and I was hoping someone could point me in the right direction:
Example snippet of JSON:
"items"
{
"0"
{
"name" "Riki's Dagger"
"prefab" "default_item"
"item_name" "#DOTA_Item_Rikis_Dagger"
"item_type_name" "#DOTA_WearableType_Daggers"
"model_player" "models/heroes/rikimaru/rikimaru_weapon.mdl"
"used_by_heroes"
{
"npc_dota_hero_riki" "1"
}
}
"1"
{
"name" "Anti-Mage's Glaive"
"prefab" "default_item"
"item_description" "#DOTA_Item_Desc_AntiMages_Glaives"
"item_name" "#DOTA_Item_AntiMages_Glaive"
"item_type_name" "#DOTA_WearableType_Glaive"
"model_player" "models/heroes/antimage/antimage_weapon.mdl"
"used_by_heroes"
{
"npc_dota_hero_antimage" "1"
}
}
I am using the following to serialize this to my own classes as follows:
DotaItemsGameResult itemGameResult
= JsonConvert.DeserializeObject<DotaItemsGameResult>(rawItemDetailsJson);
This is working OK as I have used this elsewhere.
The trouble comes here:
string dataToDisplay = "";
foreach (DotaItemsGameItem item in itemGameResult.Items_Game.Items.Item_Index)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
return dataToDisplay;
My code seems to know about itemGameResult.Items_Game.Items but not when I want to go further into .Items_Index.
I have the following classes:
public class DotaItemsGameResult
{
public DotaItemsGameResultProperties Items_Game { get; set; }
}
public class DotaItemsGameResultProperties
{
public List<DotaItemsGameRarities> Rarities { get; set; }
public List<DotaItemsGameItems> Items { get; set; }
}
public class DotaItemsGameItems
{
public List<DotaItemsGameItem> Item_Index { get; set; }
}
public class DotaItemsGameItem
{
public string Name { get; set; }
public string Hidden { get; set; }
public string Item_Class { get; set; }
public string Item_Name { get; set; }
public string Item_Slot { get; set; }
public string Item_Quality { get; set; }
public string Min_Ilevel { get; set; }
public string Max_Ilevel { get; set; }
public string Item_Description { get; set; }
public string Item_Type_Name { get; set; }
public List<DotaItemsGameUsedByHero> Used_By_Heroes { get; set; }
}
Basically, my aim is to be able to get at the Used_By_Heroes data in my loop but I can't.
In my for each, itemGameResult.Items_Game.Items is fine, but itemGameResult.Items_Game.Items.Item_Index is not and I can't see why.
I can't access the the Item_Index when I use dot notation, there's no Item_Index where I would expect there to be. If I put it in anyway and try to compile, I see this:
Error 1 'System.Collections.Generic.List' does not contain a definition for 'Item_Index' and no extension method 'Item_Index' accepting a first argument of type 'System.Collections.Generic.List' could be found (are you missing a using directive or an assembly reference?).
Any help would be fantastic.
Problem is that the Items property of the class DotaItemsGameResultProperties is a collection (List<DotaItemsGameItems>) so it doesn't have a property Item_Index. Not sure what do you want to achieve, but one possibility to fix this is to iterate on this collection also:
string dataToDisplay = "";
foreach (DotaItemsGameItems items in itemGameResult.Items_Game.Items)
{
foreach (DotaItemsGameItem item in items.Item_Index)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
}
return dataToDisplay;
This is to illustrate the structure of your data, you can do this in a more concise way:
string dataToDisplay = "";
var allItems = itemGameResult.Items_Game.Items.SelectMany(i => i.Item_Index);
foreach (DotaItemsGameItem item in allItems)
{
dataToDisplay += "<h3> Item: " + item.Name + "</h3>";
dataToDisplay += "<p> Quality: " + item.Item_Quality + "</p>";
dataToDisplay += "<p> Attributes: " + item.Used_By_Heroes + "</p>";
}
return dataToDisplay;

Categories

Resources