need to include school entity within classroom entity - c#

I have 2 lists School & Classroom like below,
public static class WebApiData
{
public static List<School> GetAllSchools()
{
List<School> schools = new List<School>
{
new School
{
id = 1,
name = "Fort Craig Elementary",
principal = "Michelle Thorne"
},
new School
{
id = 2,
name = "Edgewood Elementary",
principal = "Audrey Hills"
}
};
return schools;
}
public static List<Classroom> GetAllClassrooms()
{
List<Classroom> classrooms = new List<Classroom>
{
new Classroom
{
id = 1,
name = "Mrs. Cox's 2nd Grade",
teacher = "Beth Cox",
school_id = 1
},
new Classroom
{
id = 2,
name = "Mr. Elliott's Kindergarten",
teacher = "Martin Elliott",
school_id = 1
},
new Classroom
{
id = 3,
name = "Mrs. Smith's 1st Grade",
teacher = "Amanda Smith",
school_id = 2
}
};
return classrooms;
}
}
Now I need to get all Classrooms along with entire school entity as a property of Classroom?
I tried join,
var result = from l1 in classrooms
join l2 in schools
on l1.school_id equals l2.id
select l1;
But instead of single property of school, I need entire school entity as a property of classroom in projection result?
Thanks,

Well, you could do in a different way. Make School a property of Classroom, instead of having the id only .
Then you can do what you want and create a single list with all the information.
Or even better, make Classroom a property of School. That makes more sense from an object abstraction point of view. Then you can build a list of all the classrooms in a school easily.
your School could look like this :
public class School
{
public int Id { get; set; }
public string Name { get; set; }
public List<Classroom> Classrooms { get; set; }
}
then you could instantiate your schools like this :
public static List<School> GetAllSchools()
{
List<School> schools = new List<School>
{
new School
{
Id =1 ,
Name = "1",
Classrooms = new List<Classroom> { new Classroom { Id = 1, Name = "1" }, new Classroom { Id = 2, Name = "2" } }
},
new School
{
Id =2 ,
Name = "2",
Classrooms = new List<Classroom> { new Classroom { Id = 3, Name = "3" }, new Classroom { Id = 4, Name = "4" } }
}
};
return schools;
}

You have two options.
Option 1
Include both object in your Select statement, you have an anonymous type with two properties, one represents ClassRoom and other School.
// Approach 1
var results = from l1 in classrooms
join l2 in schools
on l1.school_id equals l2.id
select new {l1, l2 };
Option 2
Create an anonymous data type with combined properties.
// Appraoch 2
var results = from l1 in classrooms
join l2 in schools
on l1.school_id equals l2.id
select new {
Id= l1.id,
Name = l1.name,
Teacher = l1.teacher,
SchoolId = l2.id,
SchoolName = l2.name,
Principal = l2.principal
};
Check working Example

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

C# LINQ get max element in group by column of another collection

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

Sort a list using a search string

I am trying to sort a list on the basis of a search string. But there seems to be some issue.
Below is the code:
namespace ListDemo
{
class Program
{
static void Main(string[] args)
{
Employee e1 = new Employee {ID=1,Name="John",City="London" };
Employee e2 = new Employee { ID = 2, Name = "Mary", City = "NY" };
Employee e3 = new Employee { ID = 3, Name = "Dave", City = "Sydney" };
Employee e4 = new Employee { ID = 4, Name = "Kate", City = "Chicago" };
Employee e5 = new Employee { ID = 5, Name = "Sheela", City = "Delhi" };
List<Employee> listEmployee = new List<Employee>();
listEmployee.Add(e1);
listEmployee.Add(e2);
listEmployee.Add(e3);
listEmployee.Add(e4);
listEmployee.Add(e5);
Console.WriteLine("Enter the name via which you wana sort?");
string searchString = Console.ReadLine();
Console.WriteLine("####################Sorted List Starts##############");
var items = from element in listEmployee
orderby element.Name.Equals(searchString)
select element;
foreach (var i in items)
{
Console.WriteLine(i.Name);
}
Console.ReadLine();
}
}
class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
}
I have an Employee class with 3 public properties, ID, Name and City.
I created a list of Employees with some dummy data in it.
Now I want the user to enter a search string, which will actually be a name, and if the list contains that name, it should sort the list as according to the search string.
For ex: if a user has entered name as 'John', then the revised list should show John as first item and so on.
The code which I have written behaves abnormally.
Image is attached:
Firstly, sort by equals in descending order (it means, that it will be firt in result), and others sort by ID to save original order (or, you can use any other property for ordering):
var items = listEmployee
.OrderByDescending(e => e.Name.Equals(searchString))
.ThenBy(e => e.ID).ToArray();

Query values in a Dictionary<ObjectId, Class> using LINQ?

Consider the following simple example of Students and Teachers;
// person
public class Person
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public Person() {
Id = ObjectId.GenerateNewId(DateTime.Now);
}
}
// student has a Classroom
public class Student : Person
{
public string Classroom { get; set; }
}
// teacher has a Dictionary<ObjectId, Student> Students
public class Teacher : Person
{
[BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
public Dictionary<ObjectId, Student> Students { get; set; }
public Teacher() {
Students = new Dictionary<ObjectId, Student>();
}
}
class Program
{
static void Main(string[] args)
{
var server = MongoServer.Create("mongodb://localhost/database?safe=true");
var database = server.GetDatabase("sandbox");
var collection = database.GetCollection<Teacher>("teachers");
collection.Drop();
// create students
var s1 = new Student() { Name = "s1", Classroom = "foo" };
var s2 = new Student() { Name = "s2", Classroom = "foo" };
var s3 = new Student() { Name = "s3", Classroom = "baz" };
var s4 = new Student() { Name = "s4", Classroom = "foo" };
// teacher 1
var t1 = new Teacher() { Name = "t1" };
t1.Students.Add(s1.Id, s1);
t1.Students.Add(s2.Id, s2);
collection.Insert(t1);
// teacher 2
var t2 = new Teacher {Name = "t2"};
t2.Students.Add(s3.Id, s3);
collection.Insert(t2);
// add teacher 3
var t3 = new Teacher() {Name = "t3"};
t3.Students.Add(s4.Id, s4);
collection.Insert(t3);
// select via key
var onlyt1 = collection.AsQueryable().Where(t => t.Students.ContainsKey(s1.Id)).ToList();
Console.WriteLine("onlyt1 : {0}", onlyt1.ToJson());
Console.ReadLine();
}
}
I can select via the key (shown above), but how do I find all the teachers who have students with classroom of "foo"? I want to write something like;
// select via value
var shouldBeJustT1andT3 = collection.AsQueryable().Where(t => t.Students.Values.Where(s => s.Classroom == "foo")).ToList();
You can use Any to get any teacher for whom there are students in a given classroom "foo":
List<Teacher> shouldBeJustT1andT3 = collection.Where(
teacher => teacher.Students.Any(student => student.Classroom == "foo")
).ToList();
Edit
Since Mongo's IQueryable isn't supporting Any by default, maybe you could just use Where and Count instead of Any:
List<Teacher> shouldBeJustT1andT3 = collection.Where(
teacher => teacher.Students.Where(student => student.Classroom == "foo").Count() > 0
).ToList();
Can't you have Students of type just ICollection<Person>?
Then you don't need query dictionary's values but flat objects' list, i.e. where s.ID == x && s.Classroom == "blah".
Dictionary makes sense to find object by key only, i.e. t.Students[studentId].
To find teachers: see dbaseman's answer, he's correct.

How to combine three lists of objects by primary key using linq

I'm trying to combine 3 lists of objects. I have a person list, address list and an addressRelation list.
I want to combine these lists into a new list ordered by person.id, use it as a datasource for a listview, and then be able to access the properties in the aspx page.
Is this possible?
Roughly
using System.Linq;
class Person
{
public int Id;
public string Name;
}
class Address
{
public int Id;
public string Street;
}
class PersonAddress
{
public int PersonId, AddressId;
}
public class Program
{
public static void Main(string[] args)
{
var personList = new []
{
new Person { Id = 1, Name = "Pete" },
new Person { Id = 2, Name = "Mary" },
new Person { Id = 3, Name = "Joe" }
};
var addressList = new []
{
new Address { Id = 100, Street = "Home Lane" },
new Address { Id = 101, Street = "Church Way" },
new Address { Id = 102, Street = "Sandy Blvd" }
};
var relations = new []
{
new PersonAddress { PersonId = 1, AddressId = 101 },
new PersonAddress { PersonId = 3, AddressId = 101 },
new PersonAddress { PersonId = 2, AddressId = 102 },
new PersonAddress { PersonId = 2, AddressId = 100 }
};
var joined =
from par in relations
join p in personList
on par.PersonId equals p.Id
join a in addressList
on par.AddressId equals a.Id
select new { Person = p, Address = a };
foreach (var record in joined)
System.Console.WriteLine("{0} lives on {1}",
record.Person.Name,
record.Address.Street);
}
}
Outputs:
Pete lives on Church Way
Mary lives on Sandy Blvd
Mary lives on Home Lane
Joe lives on Church Way

Categories

Resources