I got this application that reads the employee data from the database, only problem the boss of an employee is set in employee_id and not in name, which is what I am looking for.
I got a List filled with all the employees. So I am looking for a way to query it with LINQ through the list to link the employee_id to the Firstname/Lastname.
Example: The employee with the ID 1 is Nancy and her boss is Andrew, but it doesn't say Andrew it says 2. But it should say Andrew
I also added 2 images below to add to my explanation.
Listview of the employees
Reading out the list of employees into the ListView
First, load the employees into some local variable (you'll need it later):
List<Employee> employees = Database.getEmployees();
Then edit your foreach cycle:
// 'employee' is better because here it is really just one specific employee
foreach (Employee employee in employees)
Now you can get the name of the boss like this (in foreach cycle):
string boss = employees.FirstOrDefault(x => x.ID == employee.ReportsTo)?.FirstName;
(You need at least C# 6.0 for the ? operator.)
So you need to Left Join ID with Boss and get the Boss Info if found:
var employees = Database.getEmployees();
var employeesWithBoss = (from e in employees
join b in employees
on e.ID equals b.Boss into leftJoin
from boss in leftJoin.DefaultIfEmpty()
select new
{
Employee = e,
BossFirstName = boss == null ? null : boss.FirstName,
BossLastName = boss == null ? null : boss.LastName
}).ToList();
foreach (var employee in employeesWithBoss)
{
// do your normal work here, you now
// have employee.BossFirstName and employee.BossLastName
}
you can use lambda to achieve this.
class Program
{
static void Main(string[] args)
{
List<Employee> employees = new List<Employee>();
employees.Add(new Employee() { EmployeeName = "Nancy", EmployeeId = 1, BossId = 2 });
employees.Add(new Employee() { EmployeeName = "Andrew", EmployeeId = 2, BossId = 0 });
employees.Add(new Employee() { EmployeeName = "Janet", EmployeeId = 1, BossId = 2 });
var employeesWithBossName = employees.Join(employees,
emp1 => emp1.BossId,
emp2 => emp2.EmployeeId,
(emp1, emp2) => new { EmployeeName = emp1.EmployeeName, BossName = emp2.EmployeeName });
foreach (var item in employeesWithBossName)
{
Console.WriteLine("{0} {1}", item.EmployeeName, item.BossName);
}
Console.Read();
}
}
public class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int BossId { get; set; }
}
Hope this will help.
Related
I want to use sql query in a get api as:
[Route("empLevel/{id}")]
public IActionResult GetEmpHierarchy(int id)
{
List<Employee> emp = entity.Employees.ToList();
List<Employee> mngr = entity.Employees.ToList();
var query = (from e in emp
join m in mngr on e.MngId equals m.Id into tab1
from mngrN in tab1.DefaultIfEmpty()
select new Employee { Id = e, MngId = m}).ToList();
return Ok(query);
}
But I am getting an error on the line ID = e where it is saying that e cannot be converted to int.
In my models class I have:
public partial class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public double Grade { get; set; }
public int? MngId { get; set; }
public virtual SalarySplit GradeNavigation { get; set; }
}
Please give a solution.
Variable e represents an object of type Employee. You are trying to assign whole object into the property Id. Instead you should use the value in property of that e object.
var query = (from e in emp
join m in mngr on e.MngId equals m.Id into tab1
from mngrN in tab1.DefaultIfEmpty()
select new Employee { Id = e.Id, MngId = m.Id}).ToList();
Bonus: If I'm not mistaken, the filtering won't be applied there and you get either object with or without manager (both). In that case the query can be simplified:
var query = (from e in emp
select new Employee { Id = e.Id, MngId = e.MngId}).ToList();
Because e is a sort of an object and your ID is an int.
so you probably want something like this.
select new Employee { Id = e.MngId, MngId = m.Id}).ToList();
I have two custom lists.
public class Model1
{
public string EmpGuid { get; set; }
public string EmployeeName { get; set; }
public DateTime Birthdate { get; set; }
}
public class Model2
{
public string EmpGuid { get; set; }
public string EmployeeName { get; set; }
public DateTime Anniversary{ get; set; }
}
Now I create 2 lists from these classes like so :-
var List1 = new List<Model1>();
var List2 = new List<Model2>();
In my Model classes the values for EmpGuid is unique and is the same in both lists. Now I want to create one single class with the following properties
public class Model3
{
public string EmpGuid { get; set; }
public string EmployeeName { get; set; }
public DateTime Birthdate { get; set; }
public DateTime Anniversary{ get; set; }
}
Here I want to combine both the list ie. List1 and List 2 grouping them with the EmpGuid such that I have a single List of type List where I have the Birthday and anniversary for each EmpGuid.
The final output should be :-
EDIT
List 1 - EmpGuid - abc
EmpName - emp1
Birthday - something
EmpGuid - xyz
EmpName - emp2
Birthday - something2
List 2 - EmpGuid - abc
EmpName - emp1
Anniversary - somethingAnniversary
EmpGuid - mno
empName - emp3
Anniversary - somethingAnniversary3
List3 - EmpGuid - abc
EmpName - emp1
Birthday - something
Anniversary - somethingAnniversary
EmpGuid - xyz
EmpName - emp2
Birthday - something2
Anniversary - null
EmpGuid - mno
EmpName - emp3
Birthday - null
Anniversary - somethingAnniversary3
How can I achieve this?
Any help is appreciated
You can do this by using LINQ's Join method:
var List3 = List1.Join(List2, l1 => l1.EmpGuid, l2 => l2.EmpGuid,
(l1, l2) => new Model3 {
EmpGuid = l1.EmpGuid,
EmployeeName = l1.EmployeeName,
BirthDate = l1.BirthDate,
Anniversary = l2.Anniversary}).ToList();
This combines the two lists by comparing the EmpGuids and creates for each combination a new Model3 instance.
One problem is that you said the EmployeeName can be different, so you have to decide which one you take or how you combine them.
Unfortunatly there is no full outer join in LINQ, so you will need to this a little more manually. One possibility is to add the missing elements after the above query like this:
List3.AddRange(List1.Where(l1 => List2.All(l2 => l1.EmpGuid != l2.EmpGuid)
.Select(l1 => new Model3 {
EmpGuid = l1.EmpGuid,
EmployeeName = l1.EmployeeName,
BirthDate = l1.BirthDate,
Anniversary = null}));
and the same the other way around:
List3.AddRange(List2.Where(l2 => List1.All(l1 => l1.EmpGuid != l2.EmpGuid)
.Select(l2 => new Model3 {
EmpGuid = l2.EmpGuid,
EmployeeName = l2.EmployeeName,
Anniversary = l2.Anniversary}));
This takes all elements from the one list with GUIDs that don't appear in the second list and creates the appropriate Model3 instances. (Note that DateTime is a value type and cannot be null, by default it's DateTime.MinValue).
You will make a join on both lists, similar to SQL:
var result = from m1 in list1
join m2 in list2 on m1.EmpGuid == m2.EmpGuid
select new Model3 { EmpGuid = m1.EmpGuid, EmployeeeName = m1.EmployeeName ...};
However this will allways use the EmployseeName from Model1. If you want to select both names you can use this approach;
var result = from m1 in list1
join m2 in list2 on m1.EmpGuid == m2.EmpGuid
select new Model3
{
EmpGuid = m1.EmpGuid,
EmployeeeName1 = m1.EmployeeName,
EmployeeeName2 = m2.EmployeeName,
...
};
Also have a look at the MSDN.
I am new to LINQ and sorry if my question have been asked
I have 2 classes
public class Person
{
int ID {get;set;}
string FirstName {get;set;}
string LastName {get;set;}
}
and
public class House
{
int ID {get;set;}
string Address {get;set;}
string ZipCode {get;set;}
int PersonId {get;set;}
}
I am saving the list of houses in a IEnumerable List
IEnumerable<House> ListHouses = GetAllHouses();
GetAllHouses return the list of houses from the database
I want to use Lamda select in LINQ in order to do the following
var st = ListHouses .Select(h => new
{
id = h.ID,
Address= h.Address,
Zip= h.ZipCode ,
PersonFirstName = GetPersonByID(h.PersonId ).FirstName,
PersonLastname = GetPersonByID(h.PersonId ).lastname
});
Where GetPersonByID returns an object of Type Person that has the given ID. and then I take his first name and last name.
My question is this:
Instead of Getting the Person 2 times for the variables (personFirstName and PersonLastName) Is there a way I can get it one time and then used it. Something like
PersonForId = GetPersonByID(h.PersonId)
PersonFirstName = PersonLastName.FirstName,
PersonLastname = PersonLastName.lastname
I'm looking for something similar to Join in SQL where you join a value from another table.
Thanks you very much for any help
You're extremely close! Using your code (and making all properties on House and Person public), here is a method using the LINQ Join method:
var st = GetAllHouses().Join(GetAllPersons(),
outerKey => outerKey.PersonId,
innerKey => innerKey.ID,
(house, person) => new
{
house.ID,
house.Address,
house.ZipCode,
PersonFirstName = person.FirstName,
PersonLastname = person.LastName
});
Note: I would recommend the GetAllPersons() and the GetAllHouses() methods return IQueryable rather than IEnumerable. Doing so will build the expression (including the join), which means LINQ-to-SQL (or Entities) will build a proper SQL statement with the JOIN included, instead of enumerating the collections and then joining.
Additional information on such can be found here: Returning IEnumerable<T> vs. IQueryable<T>
using System;
using System.Linq;
class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
class Order
{
public int ID { get; set; }
public string Product { get; set; }
}
class Program
{
static void Main()
{
// Example customers.
var customers = new Customer[]
{
new Customer{ID = 5, Name = "Sam"},
new Customer{ID = 6, Name = "Dave"},
new Customer{ID = 7, Name = "Julia"},
new Customer{ID = 8, Name = "Sue"}
};
// Example orders.
var orders = new Order[]
{
new Order{ID = 5, Product = "Book"},
new Order{ID = 6, Product = "Game"},
new Order{ID = 7, Product = "Computer"},
new Order{ID = 8, Product = "Shirt"}
};
// Join on the ID properties.
var query = from c in customers
join o in orders on c.ID equals o.ID
select new { c.Name, o.Product };
// Display joined groups.
foreach (var group in query)
{
Console.WriteLine("{0} bought {1}", group.Name, group.Product);
}
}
}
Output
Sam bought Book
Dave bought Game
Julia bought Computer
Sue bought Shirt
I have an employee class that has an employeeId (int), parent(int) and children property List<Employee>. I get the employee list from the database in the correct order and now need to build the hierarchy, but I am failing miserably...I know this is programming 101, but I am having a hard time with it.
public class Employee
{
public int EmployeeId { get; set;}
public int ParentId;{ get; set;}
public List<Employee> Children; { get; set;}
}
Data Example
EmployeeId, ManagerId
1, 0 //no one
2, 1
3, 1
4, 2
5, 2
6, 3
7, 3
List<Employee> allEmployees = new List<Employee>();
allEmployees.AddRange(LoadAllEmployees()); // pull from DB in flat format
foreach (var employee in allEmployees)
{
employee.Children = allEmployees.Where(e => e.ParentId == employee.EmployeeId).ToList();
}
You can start by creating a list of all the employee objects and setting the EmployeeId and ParentId properties. If you also put them in a dictionary, keyed by EmployeeId, you can retrieve the parent of each afterward to add to the Children collection:
List<Employee> employees = new List<Employee>();
Dictionary<int,Employee> dict = new Dictionary<int,Employee>();
foreach(result from database query)
{
Employee employee = new Employee();
employee.EmployeeId = result["EmployeeId"];
employee.ParentId = result["ParentId"];
employees.Add(employee);
dict.Add(employee.EmployeeId, employee);
}
foreach(Employee e in employees)
{
dict[e.ParentId].Children.Add(e);
}
i got inspiration from this article a while ago (i had to change it slightly to suit my purposes). It basically builds a hierarchical structure to the n'th degree.
Might be useful, even if only to discount its approach in your own case :-)
http://www.scip.be/index.php?Page=ArticlesNET23&Lang=EN
Suppose each Person has a collection of favorite Books.
So I have a table for:
Person
Book
The association between Person and Book (joint table for MxN)
I want to fetch the Persons that are similar to a Person1 based on the favorite Books overlaping. That is: The more books they have in common, the more they are similar.
I don't have to use only SQL to solve this problem. I could use programming also. I'm using SQL Server 2008 and C#.
What solution would you experts use?
This may not be the most efficient, but it's relatively simple:
WITH SimlarBookPrefs(person_id, similar_person_id, booksInCommon) AS
(
Select p1.person_id, p2.person_id AS simlar_person_id,
/* Find the number of books p1 and p2 have in common */
(SELECT COUNT(*) FROM PersonBook pb1, PersonBook pb2
JOIN pb1=book_id=pb2.book_id
WHERE pb1.person_id=p1.person_id AND pb2.person_id=p2.person_id) As BooksInCommon
FROM Person p1 CROSS JOIN Person p2
)
This will give you for each person, a list of other persons and the number books in common.
To get the most similar person, add (in the same query)
SELECT TOP 1 similar_person_id FROM SimilarBookPrefs
WHERE person_id = <person_to_match>
ORDER By booksInCommon DESC;
The first part does not have to be a CTE (i.e. WITH ...) it can be a view or even a derived table. It'a a CTE here for brevity.
If I were doing this in C#, I might tackle it like this
var query = from personBook in personBooks
where personBook.PersonId != basePersonId // ID of person to match
join bookbase in personBooks
on personBook.BookId equals bookbase.BookId
where bookbase.PersonId == basePersonId // ID of person to match
join person in persons
on personBook.PersonId equals person.Id
group person by person into bookgroup
select new
{
Person = bookgroup.Key,
BooksInCommon = bookgroup.Count()
};
This could likely be done with the entity framework or Linq to SQL, or simply translated into SQL directly.
Full sample code
class CommonBooks
{
static void Main()
{
List<Person> persons = new List<Person>()
{
new Person(1, "Jane"), new Person(2, "Joan"), new Person(3, "Jim"), new Person(4, "John"), new Person(5, "Jill")
};
List<Book> books = new List<Book>()
{
new Book(1), new Book(2), new Book(3), new Book(4), new Book(5)
};
List<PersonBook> personBooks = new List<PersonBook>()
{
new PersonBook(1,1), new PersonBook(1,2), new PersonBook(1,3), new PersonBook(1,4), new PersonBook(1,5),
new PersonBook(2,2), new PersonBook(2,3), new PersonBook(2,5),
new PersonBook(3,2), new PersonBook(3,4), new PersonBook(3,5),
new PersonBook(4,1), new PersonBook(4,4),
new PersonBook(5,1), new PersonBook(5,3), new PersonBook(5,5)
};
int basePersonId = 4; // person to match likeness
var query = from personBook in personBooks
where personBook.PersonId != basePersonId
join bookbase in personBooks
on personBook.BookId equals bookbase.BookId
where bookbase.PersonId == basePersonId
join person in persons
on personBook.PersonId equals person.Id
group person by person into bookgroup
select new
{
Person = bookgroup.Key,
BooksInCommon = bookgroup.Count()
};
foreach (var item in query)
{
Console.WriteLine("{0}\t{1}", item.Person.Name, item.BooksInCommon);
}
Console.Read();
}
}
class Person
{
public int Id { get; set; }
public string Name { get; set; }
public Person(int id, string name) { Id = id; Name = name; }
}
class Book
{
public int Id { get; set; }
public Book(int id) { Id = id; }
}
class PersonBook
{
public int PersonId { get; set; }
public int BookId { get; set; }
public PersonBook(int personId, int bookId) { PersonId = personId; BookId = bookId; }
}
The problem you are describing is usually referred to as "collaborative filtering" and tackled using "recommender systems". Googling for either of those terms should lead you to plenty of useful information.