why can't i access CategoryName in this example? - c#

Consider the following classes:
public class Pie
{
public int Id { get; set; }
public string Name { get; set; }
public int CategoryId { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public ICollection<Pie> Pies { get; set; }
}
I have the following data coming from hardcoded files:
public class MockPieRepository : IPieRepository
{
private readonly ICategoryRepository _categoryRepository = new MockCategoryRepository();
private List<Pie> pies = new List<Pie>() {
new Pie { Id = 1, Name = "Apple Pie", Price = 12.95M, IsPieOfTheWeek = true, ShortDescription = "Yummy Apple Pie", LongDescription = "Lengthy apple pie", ImageThumbnailUrl = "images/thumbs/apple.jpg", ImageUrl = "images/apple.jpg", CategoryId = 1},
new Pie { Id = 2, Name = "Rhubarb Pie", Price = 11.95M, IsPieOfTheWeek = false, ShortDescription = "Yummy Rhubarb Pie", LongDescription = "Lengthy Rhubarb pie", ImageThumbnailUrl = "images/thumbs/Rhubarb.jpg", ImageUrl = "images/Rhubarb.jpg", CategoryId = 1},
new Pie { Id = 3, Name = "Cheesecake", Price = 8.95M, IsPieOfTheWeek = false, ShortDescription = "Yummy Cheesecake Pie", LongDescription = "Lengthy Cheesecake pie", ImageThumbnailUrl = "images/thumbs/Cheesecake.jpg", ImageUrl = "images/Cheesecake.jpg", CategoryId = 2},
new Pie { Id = 4, Name = "Chocolate Cake", Price = 4.95M, IsPieOfTheWeek = false, ShortDescription = "Yummy Chocolate Pie", LongDescription = "Lengthy Chocolate pie", ImageThumbnailUrl = "images/thumbs/Chocolate.jpg", ImageUrl = "images/Chocolate.jpg", CategoryId = 3},
new Pie { Id = 5, Name = "Mince Beef", Price = 6.99M, IsPieOfTheWeek = false, ShortDescription = "Yummy Mince Beef Pie", LongDescription = "Lengthy Mince Beef pie", ImageThumbnailUrl = "images/thumbs/Beef.jpg", ImageUrl = "images/Beef.jpg", CategoryId = 3}
};
public IEnumerable<Pie> GetPies()
{
return pies.OrderBy(p => p.Id);
}
public Pie GetPieById(int pieId)
{
return pies.FirstOrDefault(p => p.Id == pieId);
}
}
public class MockCategoryRepository : ICategoryRepository
{
public IEnumerable<Category> Categories {
get {
return new List<Category>
{
new Category { CategoryId = 1, CategoryName = "Fruit Pies", Description = "All fruity pies"},
new Category { CategoryId = 2, CategoryName = "Cheesecakes", Description = "Cheesecakes to make your heart sing"},
new Category { CategoryId = 3, CategoryName = "Seasonal Pies", Description = "Christmas, Halloween or Spring"}
};
}
}
}
When I try to get CategoryName from #pie.Category.CategoryName the value is null. Clearly I'm doing something wrong trying to navigate to Category from Pie, but can anyone tell me what it is?
Thanks.

You never set pie.Category = category.
One of the things that EF will automatically do when it loads data, is that it will 'resolve' navigation properties that it has detected in the data.
If you save pie with a Category set, then that data will be persisted in the database, and next time pie is loaded, you will have pie.Category also loaded. As you haven't stored (and retrieved) data from a database, this has not happened.

Related

How to get data from 3 table into 1 list

Sorry for my bad English.
Here is my SQL Design.
I have 3 table in Sqlsever. Each table has 4 column with same name, same datatype.
And i want to get data from 4 column "Id, Name, Quantity, IdCategory" from 3 table into 1 list object same as returning value in this code below:
public async Task<IEnumerable<Shirt>> LoadAllShirt()
{
return await _dbContext.Shirt.ToListAsync();
}
I use .NET Core 6 Mvc - code first. Thanks for your help.
I have 3 table in Sqlsever. Each table has 4 column with same name,
same datatype. And I want to get data from 4 column "Id, Name,
Quantity, IdCategory" from 3 table into 1 list, I use .NET Core 6 Mvc - code first.
Well, lot of way around to handle this kind of scenario. Most easy and convenient way I would prefer to use View model or using Linq query.
Lets assume you have below Models:
Models:
public class Bags
{
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public string Category { get; set; }
}
public class Shirts
{
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public string Category { get; set; }
}
public class Shoes
{
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
public string Category { get; set; }
}
Seeds In Models:
List<Bags> listBags = new List<Bags>();
listBags.Add(new Bags() { Id = 101, Name = "Bag A", Quantity =10, Category = "Cat-A"});
listBags.Add(new Bags() { Id = 102, Name = "Bag B", Quantity =15, Category = "Cat-A"});
listBags.Add(new Bags() { Id = 103, Name = "Bag C", Quantity =20, Category = "Cat-A"});
List<Shirts> listShirts = new List<Shirts>();
listShirts.Add(new Shirts() { Id = 101, Name = "Shirt A", Quantity = 10, Category = "Cat-B" });
listShirts.Add(new Shirts() { Id = 102, Name = "Shirt B", Quantity = 15, Category = "Cat-B" });
listShirts.Add(new Shirts() { Id = 103, Name = "Shirt C", Quantity = 20, Category = "Cat-B" });
List<Shoes> listShoes = new List<Shoes>();
listShoes.Add(new Shoes() { Id = 101, Name = "Shirt A", Quantity = 10, Category = "Cat-S" });
listShoes.Add(new Shoes() { Id = 102, Name = "Shirt B", Quantity = 15, Category = "Cat-S" });
listShoes.Add(new Shoes() { Id = 103, Name = "Shirt C", Quantity = 20, Category = "Cat-S" });
Way: 1 using ViewModel:
public class AllViewModel
{
public List<Bags> Bags { get; set; }
public List<Shirts> Shirts { get; set; }
public List<Shoes> Shoes { get; set; }
}
Query Using ViewModel:
var allTableUsingViewModel = new AllViewModel();
allTableUsingViewModel.Bags = listBags;
allTableUsingViewModel.Shirts = listShirts;
allTableUsingViewModel.Shoes = listShoes;
Output Using ViewModel:
Way: 2 using Linq Annonymous Type:
Query Using Linq Annonymous Type:
var AllTableListUsingLinq = from a in listBags
join b in listShirts on a.Id equals b.Id
join c in listShoes on b.Id equals c.Id
select new
{
FromBagsID = a.Id,
FromBagsName = a.Name,
FromBagsQuantity = a.Quantity,
FromBagsCategory = a.Category,
FromShirtsID = b.Id,
FromShirtsName = b.Name,
FromShirtsQuantity = b.Quantity,
FromShirtsCategory = b.Category,
FromShoesID = c.Id,
FromShoesName = c.Name,
FromShoesQuantity = c.Quantity,
FromShoesCategory = c.Category
};
Output Using Linq Annonymous Type:
Full Controller:
[HttpGet("GetFrom3Tables")]
public IActionResult GetFrom3Tables()
{
List<Bags> listBags = new List<Bags>();
listBags.Add(new Bags() { Id = 101, Name = "Bag A", Quantity =10, Category = "Cat-A"});
listBags.Add(new Bags() { Id = 102, Name = "Bag B", Quantity =15, Category = "Cat-A"});
listBags.Add(new Bags() { Id = 103, Name = "Bag C", Quantity =20, Category = "Cat-A"});
List<Shirts> listShirts = new List<Shirts>();
listShirts.Add(new Shirts() { Id = 101, Name = "Shirt A", Quantity = 10, Category = "Cat-B" });
listShirts.Add(new Shirts() { Id = 102, Name = "Shirt B", Quantity = 15, Category = "Cat-B" });
listShirts.Add(new Shirts() { Id = 103, Name = "Shirt C", Quantity = 20, Category = "Cat-B" });
List<Shoes> listShoes = new List<Shoes>();
listShoes.Add(new Shoes() { Id = 101, Name = "Shirt A", Quantity = 10, Category = "Cat-S" });
listShoes.Add(new Shoes() { Id = 102, Name = "Shirt B", Quantity = 15, Category = "Cat-S" });
listShoes.Add(new Shoes() { Id = 103, Name = "Shirt C", Quantity = 20, Category = "Cat-S" });
//Way: 1 Linq Query
var AllTableListUsingLinq = from a in listBags
join b in listShirts on a.Id equals b.Id
join c in listShoes on b.Id equals c.Id
select new
{
FromBagsID = a.Id,
FromBagsName = a.Name,
FromBagsQuantity = a.Quantity,
FromBagsCategory = a.Category,
FromShirtsID = b.Id,
FromShirtsName = b.Name,
FromShirtsQuantity = b.Quantity,
FromShirtsCategory = b.Category,
FromShoesID = c.Id,
FromShoesName = c.Name,
FromShoesQuantity = c.Quantity,
FromShoesCategory = c.Category
};
//Way: 2 : ViewModel
var allTableUsingViewModel = new AllViewModel();
allTableUsingViewModel.Bags = listBags;
allTableUsingViewModel.Shirts = listShirts;
allTableUsingViewModel.Shoes = listShoes;
return Ok(AllTableListUsingLinq);
}
Note: If you need more information you could check our official document for View Model and Linq Projction here
The following sample query will list your 3 types of data into a single result set.
var allResults = resultSet1.Concat(resultSet2);
For the return type create a class which will be the parent class for all your products (Bag,Shirt,Shoes) Which will help you to return data in a single Generic data.
If you use any non-generic list to send the data like hashtable or Arraylist then then there will be no issue.
In my way I will suggest to use generic data list as it will help you fetch data in better time complexity.
In this case you may need to define additional indirect base class with these 4 parameters. Than you can create Collection of this base class, and concatinate all 3 tables into.
public class BaseEntity
{
public string Name {get;set;}
}
public class Shoes : BaseEntity
{
}
...
public IEnumerable<BaseEntity> GetAllTables()
{
var shirts = await _dbContext.Shirt.ToListAsync();
var shoes = await _dbContext.Shoes.ToListAsync();
var bags = await _dbContext.Bags.ToListAsync();
return shirts.Concat(shoes).Concat(bags);
}
Similar example but witout casting to base class is shown in Enumerable.Concat documentation: https://learn.microsoft.com/pl-pl/dotnet/api/system.linq.enumerable.concat?view=net-7.0

Why am I getting an exception when filling the database with test data (EF Core - ASP-NET Core)

I am getting an exception: "Object reference not set to an instance of an object". I can't understand, why. What's wrong with my connections between tables? I wanted to establish a relationship between the "Country" and "Company" tables in a one-to-many relationship, to avoid duplicating countries in the Company table ( This is what the table looked like before - Image3. I want to create 3 table.
Information about exception:
Image1
Information2:
Image2
The table before:
Image3
An exception occurs in the tables: "Product" - "Company" - "Country".
Seed Database:
using E_Store2021.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace E_Store2021.Data
{
public static class ApplicationDbContextSeed
{
public static async Task SeedAsync(ApplicationDbContext _context, ILoggerFactory loggerFactory)
{
try
{
_context.Database.EnsureCreated();
await SeedCategoriesAsync(_context);
await SeedSubCategories(_context);
await SeedCountry(_context);
await SeedCompany(_context);
await SeedProduct(_context);
}
catch(Exception ex)
{
var log = loggerFactory.CreateLogger<ApplicationDbContext>();
log.LogError(ex.Message);
}
}
private static async Task SeedCategoriesAsync(ApplicationDbContext _context)
{
if (_context.Categories.Any()) return;
var categories = new List<Category>()
{
new Category
{
Description = "Some category",
CategoryName = "Electronics",
ImagePath = "category_1.webp"
},
new Category
{
Description = "Some category",
CategoryName = "Computers",
ImagePath = "category_2.webp"
},
new Category
{
Description = "Some category",
CategoryName = "Music",
ImagePath = "category_3.webp"
},
new Category
{
Description = "Some category",
CategoryName = "Software",
ImagePath = "category_4.webp"
},
new Category
{
Description = "Some category",
CategoryName = "Arts",
ImagePath = "category_5.webp"
},
new Category
{
Description = "Some category",
CategoryName = "Games",
ImagePath = "category_6.webp"
},
};
_context.Categories.AddRange(categories);
await _context.SaveChangesAsync();
}
private static async Task SeedSubCategories(ApplicationDbContext _context)
{
if (_context.SubCategories.Any()) return;
var categories = await _context.Categories.ToListAsync();
var subCategories = new List<SubCategory>
{
new SubCategory
{
CategoryID = categories.FirstOrDefault(c => c.CategoryName == "Electronics").CategoryID,
SubCategoryName = "Camera",
Description = "Some"
},
new SubCategory
{
CategoryID = categories.FirstOrDefault(c => c.CategoryName == "Electronics").CategoryID,
SubCategoryName = "Phones",
Description = "Some"
},
new SubCategory
{
CategoryID = categories.FirstOrDefault(c => c.CategoryName == "Electronics").CategoryID,
SubCategoryName = "Headphones",
Description = "Some"
},
new SubCategory
{
CategoryID = categories.FirstOrDefault(c => c.CategoryName == "Electronics").CategoryID,
SubCategoryName = "Video Game Consoles && Accessories",
Description = "Some"
},
};
_context.SubCategories.AddRange(subCategories);
await _context.SaveChangesAsync();
}
private static async Task SeedProduct(ApplicationDbContext _context)
{
if (_context.Products.Any()) return;
var subCategories = await _context.SubCategories.ToListAsync();
var companies = await _context.Companies.ToListAsync();
var products = new List<Product>
{
new Product
{
ProductName = "iPhone 12 Pro Max",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Phones").SubCategoryID,
UnitPrice = 1695.66,
ImagePath = "iphone12.webp",
Description = "Some phone",
OnSale = true,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Apple").CompanyID,
},
new Product
{
ProductName = "iPhone 11 Pro Max",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Phones").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "iphone11.jpg",
Description = "Some phone",
OnSale = false,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Apple").CompanyID,
},
new Product
{
ProductName = "Xiaomi 9 Pro",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Phones").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "iphone11.jpg",
Description = "Some phone",
OnSale = false,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Xiaomi").CompanyID,
},
new Product
{
ProductName = "Canon PowerShot SX540 Digital Camera",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Camera").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "canon_sx540.jpg",
Description = "Some phone",
OnSale = false,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Canon").CompanyID,
},
new Product
{
ProductName = "Panasonic LUMIX FZ300",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Camera").SubCategoryID,
UnitPrice = 397,
ImagePath = "panasonic_fz300.jpg",
Description = "Some phone",
OnSale = false,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Panasonic").CompanyID,
},
new Product
{
ProductName = "4K Digital Camera 48MP Camera",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Camera").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "4k_digitalcamera_48mp.jpg",
Description = "Some phone",
Star = 4.5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "CEDITA").CompanyID,
},
new Product
{
ProductName = "TOZO T10 Bluetooth 5.0",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Headphones").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "tozo_t10.jpg",
Description = "Some phone",
OnSale = false,
Star = 4.6,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "TOZO").CompanyID,
},
new Product
{
ProductName = "TOZO T6 True Wireless",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Headphones").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "tozo_t6.jpg",
Description = "Some phone",
OnSale = false,
Star = 4.5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "TOZO").CompanyID,
},
new Product
{
ProductName = "Razer Kraken Tournament Edition",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Headphones").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "razer_kraken.jpg",
Description = "Some phone",
OnSale = false,
Star = 4.5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Razer").CompanyID,
},
new Product
{
ProductName = "Sony PlayStation 4 Pro (Red Dead Redemption 2 Bundle)",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Video Game Consoles && Accessories").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "playstation-4.jpg",
Description = "Some phone",
OnSale = false,
Star = 4,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Sony").CompanyID,
},
new Product
{
ProductName = "PlayStation 4 Pro 1TB Limited Edition",
SubCategoryID = subCategories.FirstOrDefault(s => s.SubCategoryName == "Video Game Consoles && Accessories").SubCategoryID,
UnitPrice = 1395.66,
ImagePath = "playstation-spider.jpg",
Description = "Some phone",
OnSale = false,
Star = 5,
Quantity = 10,
CompanyID = companies.FirstOrDefault(c => c.CompanyName == "Sony").CompanyID,
},
};
_context.Products.AddRange(products);
await _context.SaveChangesAsync();
}
private static async Task SeedCompany(ApplicationDbContext _context)
{
if (_context.Companies.Any()) return;
var countries = await _context.Countries.ToListAsync();
List<Company> companies = new List<Company>
{
new Company
{
CompanyName = "Apple",
Year = 1976,
CountryID = countries.FirstOrDefault(c => c.CountryName == "USA").CountryID
},
new Company
{
CompanyName = "Xiaomi",
Year = 2010,
CountryID = countries.FirstOrDefault(c => c.CountryName == "China").CountryID
},
new Company
{
CompanyName = "Canon",
Year = 1987,
CountryID = countries.FirstOrDefault(c => c.CountryName == "China").CountryID
},
new Company
{
CompanyName = "Panasonic",
Year = 1918,
CountryID = countries.FirstOrDefault(c => c.CountryName == "Japan").CountryID
},
new Company
{
CompanyName = "CEDITA",
Year = 2005,
CountryID = countries.FirstOrDefault(c => c.CountryName == "United Kingdom").CountryID
},
new Company
{
CompanyName = "TOZO",
Year = 2016,
CountryID = countries.FirstOrDefault(c => c.CountryName == "Spain").CountryID
},
new Company
{
CompanyName = "Razer",
Year = 2010,
CountryID = countries.FirstOrDefault(c => c.CountryName == "USA").CountryID
},
new Company
{
CompanyName = "Sony",
Year = 2000,
CountryID = countries.FirstOrDefault(c => c.CountryName == "Sony").CountryID
},
};
_context.Companies.AddRange(companies);
await _context.SaveChangesAsync();
}
private static async Task SeedCountry(ApplicationDbContext _context)
{
if (_context.Countries.Any()) return;
var countries = new List<Country>
{
new Country
{
CountryName = "Spain"
},
new Country
{
CountryName = "United Kingdom"
},
new Country
{
CountryName = "Japan"
},
new Country
{
CountryName = "China"
},
new Country
{
CountryName = "USA"
},
};
_context.Countries.AddRange(countries);
await _context.SaveChangesAsync();
}
}
}
Class Product:
using E_Store2021.ViewModels;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace E_Store2021.Models
{
public class Product
{
public int ProductID { get; set; }
[Required]
[StringLength(100)]
[Display(Name = "Name")]
public string ProductName { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
[Display(Name = "Price")]
public double UnitPrice { get; set; }
public bool OnSale { get; set; }
public double Star { get; set; }
public int Quantity { get; set; }
public int? SubCategoryID { get; set; }
public int? CompanyID { get; set; }
public virtual Company Company { get; set; }
public virtual SubCategory SubCategory { get; set; }
}
}
Class Company:
using System.Collections.Generic;
namespace E_Store2021.Models
{
public class Company
{
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public int Year { get; set; }
public int? CountryID { get; set; }
public virtual Country Country { get; set; }
public virtual ICollection<Product> Products { get; set; }
}
}
Class Country:
using System.Collections.Generic;
namespace E_Store2021.Models
{
public class Country
{
public int CountryID { get; set; }
public string CountryName { get; set; }
public virtual ICollection<Company> Companies { get; set; }
}
}
Thank you for any help.
Declare your collection navigation properties like this:
public virtual ICollection<Product> Products { get; } = new HashSet<Product>();
So they start out empty, not null.
You have the error:
new Company
{
CompanyName = "Sony",
Year = 2000,
CountryID = countries.FirstOrDefault(c => c.CountryName == "Sony").CountryID
},

How to make nested list from one base list

I would like to make nested list from this one list
public class Product
{
string Id;
string ProductName;
decimal Price;
string Supplier;
int Quantity;
string VersionId;
string TypeId;
}
public class ProductTypeDto
{
public string TypeId { get; set; }
public string ProductName { get; set; }
public string Price { get; set; }
public List<ProductVersionDto> ProductVersions { get; set; }
}
public class ProductVersionDto
{
public string VersionId { get; set; }
public string ProductName { get; set; }
public string Supplier { get; set; }
public int Quantity { get; set; }
}
I would like to know how I can create a list of ProductTypeDto using linq c# .
I need to get all products with the same TypeId , and ProductVersions field should contain products with same version Id (and of course same TypeId).
I don't want to use foreach loops, and I dont want to loop over products twice to make this nested list.. I think there would be a better way using Linq, would be great if you can help..
Edit: I add here what I have done so far, but it is not the way I want this to be fixed.
List<ProductTypeDto> products = this._dbContext
.Products
.Where(product => product.TypeId == query.TypeId)
.Select(product => new ProductTypeDto()
{
TypeId = product.TypeId,
ProductName = product.ProductName,
Price = product.Price,
ProductVersions = product.Products.Where(p => p.TypeId == product.TypeId)
.Select(p => new ProductVersionDto()
{
VersionId = p.VersionId,
ProductName = p.ProductName,
Supplier = p.Supplier,
Quantity = p.Quantity
}).ToList()
})
.ProjectTo<ProductTypeDto>(this._config)
.ToListAsync(cancellationToken);
This is the result I want to get:
var product1 = new Product() { Id = 1, ProductName = "foo", Price = 20, Supplier = "test1", Quantity = 3, VersionId = "1", TypeId = "1" };
var product2 = new Product() { Id = 2, ProductName = "foo1", Price = 60, Supplier = "test2", Quantity = 9, VersionId = "1", TypeId = "1" };
var product3 = new Product() { Id = 3, ProductName = "foo2", Price = 30, Supplier = "test3", Quantity = 5, VersionId = "2", TypeId = "1" };
var product4 = new Product() { Id = 4, ProductName = "foo3", Price = 10, Supplier = "test4", Quantity = 4, VersionId = "1", TypeId = "2" };
var product5 = new Product() { Id = 5, ProductName = "foo4", Price = 50, Supplier = "test5", Quantity = 8, VersionId = "1", TypeId = "3" };
List<ProductVersionDto> p1 = {
new ProductVersionDto { ProductName = "foo", Quantity= 3, Supplier ="test1"}
new ProductVersionDto { ProductName = "foo1", Quantity= 9, Supplier ="test2"}
};
List<ProductVersionDto> p2 = {
new ProductVersionDto { ProductName = "foo3", Quantity= 4, Supplier ="test4"}
};
List<ProductVersionDto> p3 = {
new ProductVersionDto { ProductName = "foo4", Quantity= 8, Supplier ="test5"}
};
List<ProductTypeDto> products = {
new ProductTypeDto{ ProductName = "foo", Price =20, ProductVersions = p1}
new ProductTypeDto{ ProductName = "foo1", Price =60, ProductVersions = p1}
new ProductTypeDto{ ProductName = "foo3", Price =10, ProductVersions = p2}
new ProductTypeDto{ ProductName = "foo4", Price =50, ProductVersions = p3}
}
Try this:
var dtos =
(
from p in products
group new ProductVersionDto()
{
VersionId = p.VersionId,
ProductName = p.ProductName,
Supplier = p.Supplier,
Quantity = p.Quantity
} by new { p.TypeId, p.ProductName, p.Price } into g
select new ProductTypeDto()
{
TypeId = g.Key.TypeId,
ProductName = g.Key.TypeId,
Price = g.Key.Price,
ProductVersions = g.ToList(),
}
).ToList();
It appears that you meant Price to be a decimal in ProductTypeDto, BTW.

Use LINQ to join 2 objects for each of its properties

I have created 2 models to store the results of an sql query. Now I would like to join them for each of the week's... (week1 = Record_id, week2 = Record_id)
to get a new Object in which I would have all the data from the 1st model, as well as map data from the "Category" Model to it.
I created a new Model for it, but I am not sure how to write a linq query
First Model:
public class CustomData
{
public string full_name { get; set; }
public string location { get; set; }
public int week1 { get; set; }
public int week2 { get; set; }
public int week3 { get; set; }
}
Second Model:
public class Category
{
public int Record_ID { get; set; }
public int Color{ get; set; }
public string Name { get; set; }
}
New Model for end result:
public class WeekView
{
public string full_name { get; set; }
public string location { get; set; }
public Category week1 { get; set; }
public Category week2 { get; set; }
public Category week3 { get; set; }
}
This should work:
List<CustomData> list = new List<CustomData>();
list.Add(new CustomData() { full_name = "test", location = "test", week1 = 0, week2 = 1, week3 = 2 });
list.Add(new CustomData() { full_name = "test2", location = "test2", week1 = 0, week2 = 12, week3 = 22 });
List<Category> categories = new List<Category>();
categories.Add(new Category { Color = 0, Name = "testName", Record_ID = 0 });
categories.Add(new Category { Color = 1, Name = "testName1", Record_ID = 1 });
categories.Add(new Category { Color = 2, Name = "testName2", Record_ID = 2 });
categories.Add(new Category { Color = 3, Name = "testName3", Record_ID = 12 });
categories.Add(new Category { Color = 4, Name = "testName4", Record_ID = 22 });
List<WeekView> results = new List<WeekView>();
results.AddRange(list.Select(x=>
new WeekView() { full_name = x.full_name,
location = x.location,
week1 = categories.FirstOrDefault(c => c.Record_ID == x.week1),
week2 = categories.FirstOrDefault(c => c.Record_ID == x.week2),
week3 = categories.FirstOrDefault(c => c.Record_ID == x.week3)
}));
Try out the following:
var result = (from cd in CustomDatas
join ca1 in Categories on cd.week1 equals ca.Record_ID into ca1r
from ca1 in ca1r.DefaultIfEmpty()
join ca2 in Categories on cd.week2 equals ca.Record_ID into ca2r
from ca2 in ca2r.DefaultIfEmpty()
join ca3 in Categories on cd.week3 equals ca.Record_ID into ca3r
from ca3 in ca3r.DefaultIfEmpty()
select new {
full_name = cd.full_name,
location = cd.location,
week1 = ca1,
week2 = ca2,
week3 = ca3
}

Add property in class dynamically

I have a list of product class, e.g:
{
Name = "Product 1",
Category = "TV",
Region = "China"
},
{
Name = "Product 2",
Category = "Watch",
Region = "Germany"
},
{
Name = "Product 3",
Category = "Smartphone",
Region = "USA"
}
and unsorted product price list for every year (in format product, year and amount), e.g:
Product 1, 2016, $2000
Product 2, 2016, $300
Product 1, 2017, $1800
Product 3, 2017, $500
Product 2, 2017, $290
I need to display the products with price - to show the comparison of price for every year. The end result should look like this:
Name Category Year 2016 Year 2017
Product 1 TV 2000 1800
Product 2 Watch 300 290
Product 3 Smartphone - 500
Since the price list will expand every year, therefore I plan to keep a list of string as properties in class.
List<string> Headers = new List<string> {
"Name",
"Category",
"Region"
};
foreach (string year in distinctYear)
{
Headers.Add("Y" + year);
}
Until here, I'm stuck, how can I convert them into a class, so that I could assign the value like this:
{
Name = "Product 1",
Category = "TV",
Y2016 = 2000,
Y2017 = 1800
},
{
Name = "Product 2",
Category = "Watch",
Region = "Germany",
Y2016 = 300,
Y2017 = 290
},
{
Name = "Product 3",
Category = "Smartphone",
Region = "USA",
Y2017 = 500
}
Any help or suggestion is much appreciated.
Use a dictionary where the key is the year and the value is the price.
class Product
{
public string Name { get; set; }
public string Category { get; set; }
public string Region { get; set; }
public IDictionary<int, decimal> PricePerYear { get; set; }
= new Dictionary<int, decimal>( );
}
var prod = new Product
{
Name = "Product1",
Category = "TV",
Region = "China",
};
prod.PricePerYear.Add( 2016, 2000 );
prod.PricePerYear.Add( 2017, 4500 );
OR (C#7)
Lets use some Tuples! As per Chris's comment you can also initialize the list/dictionary during creation.
class Product
{
public string Name { get; set; }
public string Category { get; set; }
public string Region { get; set; }
public IList<(int year, decimal amount)> PricePerYear { get; set; }
}
var prod = new Product
{
Name = "Product1",
Category = "TV",
Region = "China",
PricePerYear = new List<(int year, decimal amount)>
{
(year: 2016, amount: 5000),
(2017, 10000),
(2018, 5000),
}
};
(int year, decimal price) = prod.PricePerYear.First( );
Console.WriteLine( $"Year: {year} Price: {price}" );
Console.ReadLine( );
You could use a list to store the prices; for example using these two classes:
class Product
{
public string Name { get; set; }
public string Category { get; set; }
public string Region { get; set; }
public List<Price> Prices { get; set; }
}
class Price
{
public int Year { get; set; }
public decimal Amount { get; set; }
}
Then you can initialize an instance of Product as follows:
Product prod1 = new Product()
{
Name = "Product1",
Category = "TV",
Region = "China",
Prices = new List<Price>()
{
new Price()
{
Year = 2016,
Amount = 2000
},
new Price()
{
Year = 2017,
Amount = 1800
}
}
};
I combine both ProductList and PriceList classes into a dictionary:
foreach (var item in ProductList)
{
var dict = new Dictionary<string, object>();
dict["Name"] = item.Name;
dict["Category"] = item.Category;
dict["Region"] = item.Region;
foreach (var i in item.PriceList)
{
dict[i.Year] = i.Amount;
}
list.Add(dict);
}

Categories

Resources