From the tree structure get list - c#

I have a class CategoryModel in c#, which is an element of a tree:
public class CategoryModel
{
public string Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public string ParentCategoryId { get; set; }
public ICollection<string> ChildCategoriesIds { get; set; } = new List<string>();
public ICollection<string> ProductsIds { get; set; } = new List<string>();
}
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
}
The ChildCategoriesIds contains Id class CategoryModel.
The ProductsIds contains Id class Product.
How proccesed data in new classes:
public class CategoryNew
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
public IEnumerable<UidName> ChildCategories { get; set; } = new List<UidName>();
public IEnumerable<UidName> Products { get; set; } = new List<UidName>();
}
public class UidName
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
}

You can specify own constructor for CategoryNew, which will take as an argument object of class CategoryModel, in which you will set all properties of CategoryNew based on values of properties of CategoryModel:
public CategoryNew(CategoryModel cm){
// set properties
}
Then your method would be:
public List<CategoryNew> ConverModelToNew(List<CategoryModel> lstCatModel){
List<CategoryNew> lstCatNew = new List<CategoryNew>();
foreach(var item in lstCatModel){
lstCatNew.Add(new CetagoryNew(item));
}
return lstCatNew;
}

Assuming you are trying to convert one set of object to another set of objects.
First of all, I believe categories shouldl inherit UidName so you will memory more efficiently by reducing duplicate objects.
public class CategoryNew: UidName
{
public IEnumerable<CategoryNew> ChildCategories { get; set; } = new List<CategoryNew>();
public IEnumerable<UidName> Products { get; set; } = new List<UidName>();
}
public class UidName
{
public string Uid { get; set; }
public string Name { get; set; }
public string NameEng { get; set; }
public bool? IsDeleted { get; set; }
}
// first run to create products
var newProducts = products.Select(p => new UidName {
Uid = p.Id,
Name = p.Name,
NameEnd = p.NameEng
}).ToArray();
// second run to create categories with products
var newCategories = categories.Select(c => new CategoryNew {
Uid = c.Id,
Name = c.Name,
NameEng = c.NameEng,
IsDeleted = (bool?)null, //TODO
Products = newProducts.Where(p => c.ProductIds.Contains(p.Uid))
.ToList()
}).ToArray();
// last run find sub categories
foreach(var category in newCategories) {
var oldCategory = categories.First(c => c.Id == category.Uid);
category.ChildCategories = newCategories.Where(c => oldCategory.ChildCategoriesIds.Contains(c.Uid))
.ToArray();
}

Related

why does not work OrderBy method in EF core?

I want to get sorted products(table products) by 'value'(table Product Parameters) according to "ParamertomId"(table Parameters) from my model.
How to sort related data correctly?
These are my model classes:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Number { get; set; }
public double Amount { get; set; }
public double PrimeCostEUR { get; set; }
[ForeignKey("ProductTypeId")]
public int ProductTypeId { get; set; }
public virtual ProductType ProductType { get; set; }
public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();
}
public class ProductType //: BaseObject
{
public int Id { get; set; }
public string NameType { get; set; }
public ICollection<Parameter> Parameters { get; set; } = new List<Parameter>();
public ICollection<Product> Products { get; set; } = new List<Product>();
}
public class Parameter
{
public int Id { get; set; }
public string Name { get; set; }
[ForeignKey("ProductType")]
public int ProductTypeId { get; set; }
public virtual ProductType ProductType { get; set; }
public ICollection<ProductParameter> ProductParameters { get; set; } = new List<ProductParameter>();
}
public class ProductParameter
{
public int Id { get; set; }
public int ProductId { get; set; }
public virtual Product Product { get; set; }
public int ParameterId { get; set; }
public virtual Parameter Parameter { get; set; }
public string Value { get; set; }
}
These are my DTO classes needed to display the data I need.:
public class ProductDTO{
public int ProductId { get; set; }
public string Number { get; set; }
public double Amount { get; set; }
public double PrimeCostEUR { get; set; }
public int ProductTypeId { get; set; }
public string NameType { get; set; }
public ICollection<ParameterDTO> Parameters { get; set; } = new
List<ParameterDTO>();}
public class ParameterDTO {
public int Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
I receive related data from three table. This my method GetSortedProducts:
public async Task<IEnumerable<ProductDTO>> GetProducts(int id)
{
var typeParams = _context.Parameters
.Where(t => t.ProductTypeId == id)
.ToList();
var products = _context.Products
.Include(t => t.ProductParameters)
.Where(t => t.ProductTypeId == id)
.ToList();
var items = new List<ProductDTO>();
foreach (var product in products)
{
var productDTO = new ProductDTO()
{
ProductId = product.Id,
Number = product.Number,
Amount = product.Amount,
PrimeCostEUR = product.PrimeCostEUR,
ProductTypeId = product.ProductTypeId
};
foreach (var typeParam in typeParams)
{
var paramDTO = new ParameterDTO();
var value = product.ProductParameters.FirstOrDefault(t => t.ParameterId == typeParam.Id);
if (value != null)
{
paramDTO.Id = value.Id;
paramDTO.Value = value.Value;
}
paramDTO.ParameterId = typeParam.Id;
paramDTO.Name = typeParam.Name;
productDTO.Parameters.Add(paramDTO);
}
// sort products by value
productDTO.Parameters.Where(y => y.ParameterId == 4)
.OrderBy(t => t.Value).ToList();
items.Add(productDTO);
}
return items;
}
It doesn't work because LINQ never affects the original collection, so this doesn't do anything at all:
productDTO.Parameters
.Where(y => y.ParameterId == 4)
.OrderBy(t => t.Value)
.ToList();
Overall, anyway, that code is not even close to good code. Don't create Product (and others) objects just to convert them to their DTO version. Use Entity Framework properly:
var products = await _context.Products
.Where(prod => prod.ProductTypeId == id)
.Select(prod => new ProductDTO
{
ProductId = prod.ProductId,
// rest of properties...
// now get the parameters
Parameters = prod.Parameters
// assuming you want to order by value, the question isn't very clear
.OrderBy(par => par.Value)
.Select(par => new ParameterDTO
{
Id = par.Id,
// etc
})
.ToList()
})
.ToListAsync();
Compare that single database query to the multiple calls that the question's code is doing when the data is already in memory.

Querying object with list of lists of lists

I want to query the database and get a sport object containing all inner lists, but for some reason I'm missing, the select only goes 2 levels deep in lists, any deepers and the lists property have a value of null,
example of the structure
public class Sports
{
public int id { get; set; }
public string name { get; set; }
public List<League> leagues { get; set; }
}
public class League
{
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public List<Team> teams { get; set; }
}
public class Team
{
public int id { get; set; }
public string name { get; set; }
public string successrate { get; set; }
public List<Player> players { get; set; }
}
public class Player
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
}
I created property in MyAppContext file as this
public DbSet<Sports> sports { get; set; }
now when I call an item using select or linq or any other way I tried, the sport object is always 2 Dimensional, meaning it doesn't go deeper than two levels in nested lists! Example of result using var sport=db.Sports.First() the result is {"id":1,"name":"Football","leagues":null} or if I used select()
var sportQuery = db.sports.Select(
s=>new Sports(){
id=s.id,
leagues=s.leagues,
name=s.name
}).First();
I still don't get full information {"id":1,"name":"Football","leagues":[{"id":1,"name":"fc","description":"Some Leauge","teams":null},{"id":2,"name":"al","description":"League","teams":null}]}
why is that! and how to get full object like this
{"id":1,"name":"Football","leagues":[{"id":1,"name":"fc","description":"Some Leauge","teams":[{"id":1,"name":"real madrid","successrate":null,"players":[{"id":1,"name":"Cristiano Ronaldo","age":21},{"id":2,"name":"Iniesta","age":38}]},{"id":2,"name":"Barcelona","successrate":null,"players":[{"id":1,"name":"Cristiano Ronaldo","age":21},{"id":2,"name":"Iniesta","age":38}]}]},{"id":2,"name":"al","description":"League","teams":[{"id":1,"name":"real madrid","successrate":null,"players":[{"id":1,"name":"Cristiano Ronaldo","age":21},{"id":2,"name":"Iniesta","age":38}]},{"id":2,"name":"Barcelona","successrate":null,"players":[{"id":1,"name":"Cristiano Ronaldo","age":21},{"id":2,"name":"Iniesta","age":38}]}]}]}
I've been stuck for days, Please any help would be much appreciated
Try following :
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataBase db = new DataBase();
var sportQuery = db.sports.Select(s=> s.leagues.Select(l => l.teams.Select(t => t.players.Select(p => new {
playerid = p.id,
playerName = p.name,
playerAge = p.age,
teamId = t.id,
teamName = t.name,
teamSucessrate = t.successrate,
leagueId= l.id,
leagueName= l.name,
leagueDescription = l.description,
sportId = s.id,
sportName = s.name
}))
.SelectMany(p => p))
.SelectMany(t => t))
.SelectMany(l => l)
.ToList();
}
}
public class DataBase
{
public List<Sports> sports { get; set;}
}
public class Sports
{
public int id { get; set; }
public string name { get; set; }
public List<League> leagues { get; set; }
}
public class League
{
public int id { get; set; }
public string name { get; set; }
public string description { get; set; }
public List<Team> teams { get; set; }
}
public class Team
{
public int id { get; set; }
public string name { get; set; }
public string successrate { get; set; }
public List<Player> players { get; set; }
}
public class Player
{
public int id { get; set; }
public string name { get; set; }
public int age { get; set; }
}
}
problem solved using Include() and thenInclude()
https://learn.microsoft.com/en-us/ef/core/querying/related-data
however, that doesn't explain why Select() only loads one list property deep, also it seems like i should be able to load object with select only or linq

Way to create composite objects from a single (flat) database query

I am getting product data from our ERP through SQL queries whereby the returned data is very flat- at the Size level. A product has 3 levels:
Style
Colours
Sizes
A style has many colours and a colour has many sizes.
I have created the following models:
public class Ap21Style
{
public int StyleIdx;
public string StyleCode;
public IList<Ap21Clr> Clrs { get; set; } = new List<Ap21Clr>();
}
public class Ap21Clr
{
public int ClrIdx { get; set; }
public string ColourCode { get; set; }
public string ColourName { get; set; }
public string ColourTypeCode { get; set; }
public string ColourTypeName { get; set; }
public IList<Ap21Sku> Skus { get; set; } = new List<Ap21Sku>();
}
public class Ap21Sku
{
public int SkuIdx { get; set; }
public string SizeCode { get; set; }
public int SizeSequence { get; set; }
public string Barcode { get; set; }
}
My ProductResult looks like this:
public int StyleIdx { get; set; }
public int ClrIdx { get; set; }
public int SkuIdx { get; set; }
public string StyleCode { get; set; }
public string ColourCode { get; set; }
public string ColourName { get; set; }
public string SizeCode { get; set; }
public int SizeSequence { get; set; }
public string ColourTypeCode { get; set; }
public string ColourTypeName { get; set; }
public string Barcode { get; set; }
public string WebData { get; set; }
What would be an effective way to loop over the results and create the Ap21Style models whereby they are a composite object with Ap21Clr's, then at the row level, the Colours have Ap21Sku's?
Assuming something like this
List<ProductResult> products = GetPropducts();
Composing the styles would involve grouping the data by the composite keys
List<Ap21Style> results = products
.GroupBy(p => new { p.StyleIdx, p.StyleCode })
.Select(g => new Ap21Style {
StyleIdx = g.Key.StyleIdx,
StyleCode = g.Key.StyleCode,
Clrs = g.GroupBy(s => new {
s.ClrIdx,
s.ColourCode,
s.ColourName,
s.ColourTypeCode,
s.ColourTypeName
}).Select(g1 => new Ap21Clr {
ClrIdx = g1.Key.ClrIdx,
ColourCode = g1.Key.ColourCode,
ColourName = g1.Key.ColourName,
ColourTypeCode = g1.Key.ColourTypeCode,
ColourTypeName = g1.Key.ColourTypeName,
Skus = g1.Select(s => new Ap21Sku {
Barcode = s.Barcode,
SizeCode = s.SizeCode,
SizeSequence = s.SizeSequence,
SkuIdx = s.SkuIdx
}).ToList()
}).ToList()
}).ToList();

How to store specific data into list with class

i want ask about storing data into list but not all data like this,
class Category :
public class CategoryEnt
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public int ParentID { get; set; }
public bool IsDisplayed { get; set; }
public bool IsTopCat { get; set; }
public bool IsTrending { get; set; }
public int SequenceID { get; set; }
public string Filtering { get; set; }
public string ImageURL { get; set; }
}
i just want add to list CategoryID, CategoryName, ImageUrl
while (reader.Read())
{
CategoryEnt category = new CategoryEnt();
category.CategoryID = Convert.ToInt32(reader["CategoryID"]);
category.CategoryName = reader["CategoryName"].ToString();
category.ImageURL = reader["ImageURL"].ToString();
list.Add(category);
}
the right now, rest of data include but with default/null value, i dont want rest of data include to list. how to store just specific data to list? any clue?
You cannot do that Directly, but indirectly you can achieve the same by using the following code:
List<CategoryEnt> CategoryEntList = new List<CategoryEnt>();
while (reader.Read())
{
CategoryEntList.Add(new CategoryEnt(){
CategoryID = Convert.ToInt32(reader["CategoryID"]),
CategoryName = reader["CategoryName"].ToString(),
ImageURL = reader["ImageURL"].ToString(),
});
}
var requiredValues = CategoryEntList.Select(x => new
{ CategoryID = x.CategoryID,
CategoryName = x.CategoryName,
ImageURL = x.ImageURL
}).ToList();
Now requiredValues is a List that will contains only those value that you ware specified in the Select You can proceed with that;
Try a class with just the information you require. Something like:
public class Category
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
public string ImageURL { get; set; }
}
Then you can create your original class using
public class CategoryEnt
{
public Category CategoryPrimaryDetails { get; set; }
public int ParentID { get; set; }
public bool IsDisplayed { get; set; }
public bool IsTopCat { get; set; }
public bool IsTrending { get; set; }
public int SequenceID { get; set; }
public string Filtering { get; set; }
}
And your original code becomes:
List<Category> list = new List<Category>();
while (reader.Read())
{
Category category = new Category() {
CategoryID = Convert.ToInt32(reader["CategoryID"]);
CategoryName = reader["CategoryName"].ToString();
ImageURL = reader["ImageURL"].ToString()
}
list.Add(category);
CategoryEnt detailedCategory = new CategoryEnt() {CategoryPrimaryDetails = category};
}

Adding multiple different types of records in some collection and sorting them

I want to send a collection of two different Collections as a Json but in a sorted format. I am not able to do it with Linq. Need little help.And also is there any better way. Thank you!
Here is my action.
public ActionResult GetAllJobPosts()
{
var Institutes = new List<Institute>()
{
new Institute(){InstituteId="ins1",InstituteName="name1",Location="Mumbai"},
new Institute(){InstituteId="ins2",InstituteName="name2",Location="Navi Mumbai"},
new Institute(){InstituteId="ins3",InstituteName="name3",Location="Thiruvananthpuram"}
};
var Companys = new List<Company>()
{
new Company(){CompanyId="com1",CompanyName="comName1",Location="Mumbai"},
new Company(){CompanyId="com2",CompanyName="comName2",Location="Navi Mumbai"},
new Company(){CompanyId="com3",CompanyName="comName3",Location="Mumbai"}
};
var Organizations = new List<Organization>()
{
new Organization(){OrganizationId="org1",OrganizationName="orgName1",Location="Navi Mumbai"},
new Organization(){OrganizationId="org2",OrganizationName="orgName2",Location="Navi Mumbai"},
new Organization(){OrganizationId="org3",OrganizationName="orgName3",Location="Mumbai"},
};
var CompanyJobPosts = new List<CompanyJobPost>()
{
new CompanyJobPost(){CompanyId="com1",CompanyJobPostId="com1jp1",CreatedOn=System.DateTime.Now.AddDays(-2),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com1",CompanyJobPostId="com1jp2",CreatedOn=System.DateTime.Now.AddDays(-3),JobDiscription="Developer",KeySkils="C#"},
new CompanyJobPost(){CompanyId="com2",CompanyJobPostId="com2jp1",CreatedOn=System.DateTime.Now.AddDays(-5),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com2",CompanyJobPostId="com2jp2",CreatedOn=System.DateTime.Now.AddDays(-6),JobDiscription="Developer",KeySkils="C#"},
new CompanyJobPost(){CompanyId="com3",CompanyJobPostId="com3jp1",CreatedOn=System.DateTime.Now.AddDays(-7),JobDiscription="Tester",KeySkils="Sylanium"},
new CompanyJobPost(){CompanyId="com3",CompanyJobPostId="com3jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="C#"}
};
var InstituteJobPosts = new List<InstituteJobPost>()
{
new InstituteJobPost(){InstituteId="ins1",InstituteJobPostId="ins1jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="C#",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins1",InstituteJobPostId="ins1jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="Java",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins2",InstituteJobPostId="ins2jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="Java",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins2",InstituteJobPostId="ins2jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils=".Net",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins3",InstituteJobPostId="ins3jp1",CreatedOn=System.DateTime.Now.AddDays(-1),JobDiscription="Trainer",KeySkils="C#",ExtraField="MDifferent"},
new InstituteJobPost(){InstituteId="ins3",InstituteJobPostId="ins3jp2",CreatedOn=System.DateTime.Now.AddDays(-8),JobDiscription="Developer",KeySkils="Java",ExtraField="MDifferent"}
};
var allJobPosts=new List<object>();
foreach (var item in CompanyJobPosts)
{
allJobPosts.Add(new { JType = "Company", JobPost = item });
}
foreach (var item in InstituteJobPosts)
{
allJobPosts.Add(new { JType = "Institute", JobPost = item });
}
//var allJobPostsOrderdByDate=??
return Json(allJobPosts, JsonRequestBehavior.AllowGet);
}
Here are My Models just to make it simple.
namespace WebApplication1.Models
{
public class Company
{
public string CompanyId { get; set; }
public string CompanyName { get; set; }
public string Location { get; set; }
}
public class Organization
{
public string OrganizationId { get; set; }
public string OrganizationName { get; set; }
public string Location { get; set; }
}
public class Institute
{
public string InstituteId { get; set; }
public string InstituteName { get; set; }
public string Location { get; set; }
}
public class CompanyJobPost
{
public string CompanyJobPostId { get; set; }
public string CompanyId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
}
public class OrganizationJobPost
{
public string OrganizationJobPostId { get; set; }
public string OrganizationId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField2 { get; set; }
}
public class InstituteJobPost
{
public string InstituteJobPostId { get; set; }
public string InstituteId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField { get; set; }
}
}
And finally my sweet view
<input name="GetAllJobPosts" id="GetAllJobPosts" type="submit" value="Search Jobs">
<ul id="JobPostList"></ul>
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script type="text/javascript">
$("#GetAllJobPosts").click(function () {
var actionUrl = '#Url.Action("GetAllJobPosts", "Default")';
$.getJSON(actionUrl, displayDetailData);
});
function displayDetailData(response) {
if (response != null) {
for (var i = 0; i < response.length; i++) {
$("#JobPostList").append("<li>" + response[i].JType + " " + (response[i].JobPost).CreatedOn + "</li>")
}
}
}
Thank You!
Based on your comments, I can only assume the following, so will do my best to point you in the correct direction:
You do not have a common object of inheritance between the two - that is, you wish to sort them on property x, but property x, is not defined to exist in both.
So, solution? Easy: add a common interface, class or abstract class between the two that has the property you wish to sort by, then sort by it:
public interface IJobPost
{
DateTime CreatedOn { get; set; }
}
Then modify your three existing objects:
public class CompanyJobPost : IJobPost
{
public string CompanyJobPostId { get; set; }
public string CompanyId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
}
public class OrganizationJobPost : IJobPost
{
public string OrganizationJobPostId { get; set; }
public string OrganizationId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField2 { get; set; }
}
public class InstituteJobPost : IJobPost
{
public string InstituteJobPostId { get; set; }
public string InstituteId { get; set; }
public string KeySkils { get; set; }
public string JobDiscription { get; set; }
public DateTime CreatedOn { get; set; }
public string ExtraField { get; set; }
}
Lastly, the action:
var allJobPosts=new List<IJobPost>();
// Add other posts to allJobPosts here.
var allJobPostsOrderdByDate = allJobPosts.OrderBy(x => x.CreatedOn).ToList();
Note: Code is untested. LINQ query may or may not work. Did this all from memory.
Edit: You can also share any other properties you wish to force between the three of them. That is what an interface or abstract class is for. That also means you can share Description or other properties.

Categories

Resources