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
Related
I have an collection of students and collection of universities. For each university i need to pick student with highest score. I want to group universities by name and select student that got highest score in that univesity. Like this:
Country | Name | Student | Score
New York| NY University | Bob | 120
LA | LA Univesity | Tom | 140
So far i got there
return from university in Universities
join country in Countries on university.Id equals country.Id
orderby country.Name
group university by university.Name into g
select new
{
g.Key,
maxScore = g.Max(student => student.Score) <-- student.Score is only available in Students class
};
Problem is university only got access to students id i.e each Universty got only thos fields:
int Country.Id,
string Name,
int Student.Id
and problem is how do i get only 1 student with max score in that g group.
Student:
Id,
Name,
Score
Here is an example:
var countries = new List<Country>
{
new Country { CountryId = 1, Name = "Country 1" },
new Country { CountryId = 2, Name = "Country 2" }
};
var universities = new List<University>
{
new University { UniversityId = 1, CountryId = 1, Name = "University 1" },
new University { UniversityId = 2, CountryId = 1, Name = "University 2" },
new University { UniversityId = 3, CountryId = 2, Name = "University 3" },
new University { UniversityId = 4, CountryId = 2, Name = "University 4" }
};
var students = new List<Student>
{
new Student { StudentId = 1, UniversityId = 1, Name = "Student 1", Score = 50 },
new Student { StudentId = 2, UniversityId = 1, Name = "Student 2", Score = 100 },
new Student { StudentId = 3, UniversityId = 2, Name = "Student 3", Score = 100 },
new Student { StudentId = 4, UniversityId = 2, Name = "Student 4", Score = 50 },
new Student { StudentId = 5, UniversityId = 3, Name = "Student 5", Score = 100 },
new Student { StudentId = 6, UniversityId = 3, Name = "Student 6", Score = 50 },
new Student { StudentId = 7, UniversityId = 4, Name = "Student 7", Score = 50 },
new Student { StudentId = 8, UniversityId = 4, Name = "Student 8", Score = 100 }
};
var maxScoresByUniversity = from country in countries
join university in universities on country.CountryId equals university.CountryId
join student in students on university.UniversityId equals student.UniversityId
group new { country, university, student } by university.Name into g
let r = g.MaxBy(x => x.student.Score)
select new
{
Country = r.country.Name,
Name = r.university.Name,
Student = r.student.Name,
Score = r.student.Score
};
foreach (var score in maxScoresByUniversity)
{
Console.WriteLine($"{score.Country}, {score.Name}, {score.Student}, {score.Score}");
}
Note that it joins and groups all three collections. It then gets the record with the max Score from each group. This uses the MaxBy method that is only available in .NET 6 and later. If you're targeting an earlier framework, you'd need to implement that yourself or use more complex LINQ. I did ask that question in the comments for a reason.
Assume that your entity classes are as below:
public class University
{
public int Id { get; set; }
public string Name { get; set; }
public int CountryId { get; set; }
public virtual Country Country { get; set; }
public ICollection<Student> Students { get; set; }
}
public class Country
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<University> Universities { get; set; }
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Score { get; set; }
public int UniversityId { get; set; }
public virtual University University { get; set; }
}
Updated
Without a relationship, you have to join between the entities.
To get the max score of the student by university you can work with .OrderByDescending() as:
var result = (from university in context.Universities
join country in context.Countries on university.CountryId equals country.Id
join student in context.Students on university.Id equals student.UniversityId
orderby country.Name
group new { university, student, country } by university.Id into g
select new
{
CountryName = g.First().country.Name,
UniversityName = g.First().university.Name,
Student = g.Select(x => x.student)
.OrderByDescending(x => x.Score)
.First()
.Name,
MaxScore = g.Select(x => x.student)
.OrderByDescending(x => x.Score)
.First()
.Score,
}).ToList();
Demo # .NET Fiddle
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.
There is three table:
Brand Category
----------------------- --------------------------------
BrandID BrandName CategoryID CategoryName
----------------------- --------------------------------
1 Brand1 1 cat1
2 Brand2 2 cat2
Product
------------------------------------------------------------
ProductID BrandID CategoryID ProductName
------------------------------------------------------------
1 1 1 Product1
2 1 1 Product2
3 1 2 Product3
4 2 1 Product4
I want to write Llinq query to get output like below:
Brand1
|__ cat1
| |__ Product1
| |__ Product2
|
|__ Cat2
| |__ Product3
|
|__ Brand2
|__ cat1
| |__ Product4
I Wrote this query to get Product group by Category:
var query2 = db.Brands
.GroupBy(x => new { x.BrandID, x.BrandName })
.Select(x => new
{
x.Key.BrandID,
x.Key.BrandName,
ProductsNames = db.Products
.Where(p => p.BrandID == x.Key.BrandID)
.Select(p => p.ProductName).ToList()
}).ToList();
How can Group Products by Brand then by Category?
You can do this in 2 steps
//Step 1 - Join 3 lists
var query = (from p in products
join b in brands on p.BrandId equals b.Id
join c in categories on p.CategoryId equals c.Id
select new
{
b.BrandName,
c.CategoryName,
p.ProductName
}).ToList();
//Step 2 - query required results
var results = query
.GroupBy(x => new { x.BrandName, x.CategoryName })
.Select(x => new
{
Brand = x.Key.BrandName,
Category = x.Key.CategoryName,
Product = x.Select(y=>y.ProductName).ToList()
});
Console.WriteLine(JsonConvert.SerializeObject(results));
OUTPUT
[
{
"Brand": "Brand1",
"Category": "cat1",
"Product": [
"Product1",
"Product2"
]
},
{
"Brand": "Brand1",
"Category": "cat2",
"Product": [
"Product3"
]
},
{
"Brand": "Brand2",
"Category": "cat1",
"Product": [
"Product4"
]
}
]
I wrote a little console program:
class Program
{
static void Main(string[] args)
{
var products = new List<Product>{
new Product { ProductID = 1, BrandID = 1, CategoryID = 1, ProductName = "Product1" },
new Product { ProductID = 2, BrandID = 1, CategoryID = 1, ProductName = "Product2" },
new Product { ProductID = 3, BrandID = 1, CategoryID = 2, ProductName = "Product3" },
new Product { ProductID = 4, BrandID = 2, CategoryID = 1, ProductName = "Product4" }
};
var groupedByBrand =
products
.GroupBy(p => p.BrandID)
.Select(g => g.GroupBy(p => p.CategoryID));
foreach (var groupByBrand in groupedByBrand)
foreach (var groupByCategory in groupByBrand)
foreach (var product in groupByCategory)
Console.WriteLine($"{product.BrandID} - {product.ProductName}");
}
}
public class Product
{
public int ProductID { get; internal set; }
public int BrandID { get; internal set; }
public int CategoryID { get; internal set; }
public string ProductName { get; internal set; }
}
I grouped by BrandId and then inside this group grouped by categoryId.
If it is just about the grouping you can use the BrandID and CategoryID and don't even need to join the tables. if you want to sort by name then of course you need to join.
Maybe you wanted to do some sorting on top of / instead of grouping?
In one step , more compact manner
public class Product
{
public int ProductID { get; internal set; }
public string ProductName { get; internal set; }
public Brand brand { get; set; }
public Category cat { get; set; }
public Product()
{
brand = new Brand();
cat = new Category();
}
}
public class Brand
{
public int BrandID { get; internal set; }
public string BrandName { get; internal set; }
}
public class Category
{
public int CategoryID { get; internal set; }
public string CategoryName { get; internal set; }
}
private void a1()
{
var products = new List<Product>{
new Product { ProductID = 1,
brand =new Brand { BrandID = 1, BrandName = "Brand1" },
cat = new Category { CategoryID = 1, CategoryName = "cat1" },
ProductName = "Product1" },
new Product { ProductID = 2,
brand =new Brand { BrandID = 1, BrandName = "Brand1" },
cat = new Category { CategoryID = 1, CategoryName = "cat1" },
ProductName = "Product2" },
new Product { ProductID = 3,
brand =new Brand { BrandID = 1, BrandName = "Brand1" },
cat = new Category { CategoryID = 2, CategoryName = "cat2" },
ProductName = "Product3" },
new Product { ProductID = 4,
brand =new Brand { BrandID = 2, BrandName = "Brand2" },
cat = new Category { CategoryID = 1, CategoryName = "cat1" },
ProductName = "Product4" }
};
var g1 = products.GroupBy(p => new { p.brand, p.cat, p })
.Select(y => new
{
k1 = y.Key.brand.BrandName,
k2 = y.Key.cat.CategoryName,
k3 = y.Key.p.ProductName
}
);
}
// Result/Output as below
{ k1 = "Brand1", k2 = "cat1", k3 = "Product1" }
{ k1 = "Brand1", k2 = "cat1", k3 = "Product2" }
{ k1 = "Brand1", k2 = "cat2", k3 = "Product3" }
{ k1 = "Brand2", k2 = "cat1", k3 = "Product4" }
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);
}
I'm trying to create following output in ASP web API:
User[]
--> Category[]
--> Transaction[]
So I have many user with several categories and a lot of transaction linked to the category.
It seems easy but I can't get it to work due to the following problem:
My database model is the following:
//Transaction
TransactionID
Quantity
CategoryID
UserID
//Category
ID
Name
//User
ID
Name
The problem is returning a json/xml response with for example:
User1
--Cate1
----Tran1
----Tran2
--Cate2
----Tran3
User2
--Cate1
----Tran4
Because there is no separate link between User and Category only with transaction and I don't know how I can fix this with LINQ queries or something else.
--Edit
My Controller code:
List<User> Users = new List<User> {
new User {Id = 1, Name = "Matt" },
new User {Id = 2, Name = "Bill" },
new User {Id = 3, Name = "Peter" },
new User {Id = 4, Name = "Bart" }
};
List<Category> Categories = new List<Category> {
new Category {Id = 1, Name = "Sales" },
new Category {Id = 2, Name = "After Sales" },
new Category {Id = 3, Name = "Pre Sales" }
};
List<Transaction> Transactions = new List<Transaction> {
new Transaction {Id = 1, Quantity = 200, CategoryId = 1 , UserId = 1},
new Transaction {Id = 2, Quantity = 150, CategoryId = 2 , UserId = 1 },
new Transaction {Id = 3, Quantity = 300, CategoryId = 2 , UserId = 1 },
new Transaction {Id = 4, Quantity = 100, CategoryId = 1 , UserId = 2},
new Transaction {Id = 5, Quantity = 150, CategoryId = 2 , UserId = 2 },
new Transaction {Id = 6, Quantity = 250, CategoryId = 3 , UserId = 3 },
new Transaction {Id = 7, Quantity = 200, CategoryId = 1 , UserId = 4},
new Transaction {Id = 8, Quantity = 50, CategoryId = 2 , UserId = 4 },
new Transaction {Id = 9, Quantity = 250, CategoryId = 3 , UserId = 4 }
};
//(new int[] { 2, 3, 5 });
public List<UserDTO> Get()
{
var User = from d in Users
select new UserDTO
{
User = d,
/* Here I have the Problem
* I can't link the categories to the users without calling all transactions
* And then the result will for UserId = 1 will return 3 categories but 2 times After Sales and I want to return it onces
*/
Categories = (from c in Transactions
where c.UserId == d.Id
select new CategoryDTO
{
Category = c.Category,
Transactions = (from t in Transactions
where t.CategoryId == c.CategoryId && t.UserId == c.UserId
select new TransactionDTO
{
Id = t.Id,
Quantity = t.Quantity
}).ToList()
}).ToList()
};
return User.ToList();
}
All the DTO classes:
public class UserDTO
{
public User User { get; set; }
public List<CategoryDTO> Categories { get; set; }
}
public class CategoryDTO
{
public Category Category { get; set; }
public List<TransactionDTO> Transactions { get; set; }
}
public class TransactionDTO
{
public int Id { get; set; }
public int Quantity { get; set; }
}
Thanks
You'll need to group by Category in order to produce the output you want:
var User = from d in Users
select new UserDTO
{
User = d,
Categories = (from t in Transactions
where t.UserId == d.Id
group t by t.Category into g // <-- group by category
select new CategoryDTO
{
Category = g.Key,
Transactions = from ct in g
select new TransactionDTO
{
Id = ct.Id,
Quantity = ct.Quantity
}).ToList()
}).ToList()
};
return User.ToList();
Note that if your object model had navigation properties it would be a little simpler:
var User = from d in Users
select new UserDTO
{
User = d,
Categories = (from t in d.Transactions
group t by t.Category into g // <-- group by category
select new CategoryDTO
{
Category = g.Key,
Transactions = from ct in g
select new TransactionDTO
{
Id = ct.Id,
Quantity = ct.Quantity
}).ToList()
}).ToList()
};
return User.ToList();
Another option would be to use a sub-model to group transactions into categories - that might reduce some of the confusion of having users linked directly to categories (when they really belong to transactions).