C# Linq finding value - c#

I want to return the depart number that is not found Employee Table by comparing Department table.
Person Table
ID name salary job commision DeptID
--------------------------------------------------------------
P001 Jon 2000 Manager NULL 1
P002 Skeet 1000 Salesman 2000 1
P003 James 2340 Developer NULL 2
P004 greed 4500 Developer NULL 2
P005 Joel 1330 Salesman 1200 1
P006 Deol 5000 Architect NULL 2
Department Table
DeptID DeptName
1 Management
2 Software
3 ERP
SQL
select DeptId from dept
where deptId not in (select deptid from person)
When i try to execute the below code
LINQ
var qry = from n in context.Persons
where n.DeptID !=
(from m in context.Depts select m.DeptId)
select new { DeptID = n.DeptID };
I receive the following error
Operator '!=' cannot be applied to operands of type 'int?' and 'System.Linq.IQueryable'

var qry = from n in context.Persons
where n.DeptID !=
(from m in context.Depts select m.DeptId).FirstOrDefault()
select new { DeptID = n.DeptID };
You are trying to compare DeptID with a collection 1 or more department Ids. Even if there would only logically be one result for a DeptID, syntactically you need to specify that you want the first hit.

Suggested rephrasing:
var q = from m in context.Depts
where
!context.Persons.Select(p => p.DeptID).Contains(m.DeptID)
select new { DeptID = m.DeptID };

It sounds that your DeptID field in SQL is set to allow nulls. In that case you'd probably want something along the lines of this:
var qry = from n in context.Persons
where n.DeptID.Value !=
(from m in context.Depts select m.DeptId)
select new { DeptID = n.DeptID.Value };

I think it should be something like that. I tried to get a list of DeptID's first and then implement a NOT IN with contains :
var deptIDs = context.Persons
.Where( p => !context.Depts
.Select(d => new {DeptID = d.DeptID})
.Contains( p.DeptID )
)
.Select( p => new { DeptID = n.DeptID } );

Related

EF Core 3.0 - Convert SQL to LINQ

The example given in the blog has the following
from e in s.StudentCourseEnrollments where courseIDs.Contains(e.Course.CourseID) select e
The contains logic will not work when we are looking for an exact match. If a student has enrolled for 6 courses (ex : 1,2,3,4,5,6) and the requested list contains 5 (ex: 1,2,3,4,5) the query will return a match when it should not. The other way works well when the student has enrolled in a subset of the requested list.
Below solution works but need help to convert the below sql to LINQ (EF Core 3.0) ?
Create TABLE dbo.Enrollments (StudentId INT NOT NULL, CourseId INT NOT NULL)
insert into dbo.Enrollments values (1,1)
insert into dbo.Enrollments values (1,2)
insert into dbo.Enrollments values (1,3)
insert into dbo.Enrollments values (1,4)
insert into dbo.Enrollments values (1,5)
insert into dbo.Enrollments values (1,6)
DECLARE #TempCourses TABLE
(
CourseId INT
);
INSERT INTO #TempCourses (CourseId) VALUES (1), (2), (3),(4),(5);
SELECT t.StudentId
FROM
(
SELECT StudentId, cnt=COUNT(*)
FROM dbo.Enrollments
GROUP BY StudentId
) kc
INNER JOIN
(
SELECT cnt=COUNT(*)
FROM #TempCourses
) nc ON nc.cnt = kc.cnt
JOIN dbo.Enrollments t ON t.StudentId = kc.StudentId
JOIN #TempCourses n ON n.CourseId = t.CourseId
GROUP BY t.StudentId
HAVING COUNT(*) = MIN(nc.cnt);
drop table dbo.Enrollments
db<>Fiddle
I don't know about the SQL query, but the EF Core 3.0 LINQ query for the same task is something like this:
var matchIds = new[] { 1, 2, 3, 4, 5 }.AsEnumerable();
var query = dbContext.Students
.Where(s => s.Enrollments.All(e => matchIds.Contains(e.CourseId))
&& s.Enrollments.Count() == matchIds.Count());
The main matching job is done with All subquery. Unfortunately that's not enough for the case when related link records are more than the matching ids, so additional counts comparison solves that.
You can achieve it with a simple way like this, live demo here
Let's say that you've got the list of enrollments by this way
var enrollments = from s in dc.Students
from c in s.Courses
select new { StudentID = s.StudentID, CourseID = c.CourseID };
Then get the result by this way
var groupedEnrollment = enrollments.GroupBy(p => p.StudentId)
.Select(g => new
{
StudentId = g.Key,
Courses = g.Select(p => p.CourseId).ToArray()
});
var result = groupedEnrollment.Where(g =>
g.Courses.Length == courses.Length &&
g.Courses.Intersect(courses).Count() == courses.Length);

Linq to Sql Union statement

I have two resultsets that I'm trying to union on (LINQ to SQL/Entity)
var ldrSet = (from ldr in Leader
join emp in employee
on ldr.ID equals emp.ID
where ldr.ID.Contains("123")
select new {ID = ldr.ID, Name = emp.firstName + " " + emp.lastName, flag = "Edit"});
var allEmpSet = (from emp in employee
where emp.ID.Contains("123")
select new {ID = ldr.ID, Name = emp.firstName + " " + emp.lastName, flag = "New"});
var results = ldrSet.Union(allEmpSet);
When I run this query I get something like this:
123 Joe Blow Edit
123 Joe Blow New
234 Jane Smith New
345 John Doe New
I understand why this is occurring but is there a way to further filter this resultset down by just using ID?
I want one record to return and the Edit record trumps the New record. So I just want this:
123 Joe Blow Edit
234 Jane Smith New
345 John Doe New
The proper way to handle things in this case isn't a Union. It's to use a left outer join instead of the inner join that LINQ defaults to. That will allow you to select all of the rows a single time and set the flag if data was matched appropriately:
var results = from e in employee
join l in leaders on l.ID equals e.ID into ls
from l in ls.DefaultIfEmpty()
select new {
e.ID,
Name = e.firstName + e.lastName,
flag = (p == null ? "New" : "Edit")
};
You can use GroupBy to group records by their ID and select just one of them:
var results = ldrSet.Union(allEmpSet)
.GroupBy(item => item.ID, (key, items) =>
items.OrderBy(item => item.flag)
.FirstOrDefault());
You can change the contents of OrderBy to determine which of the items to choose.

How can I get this result using linq?

I currently have two tables: a table of Users and a table of Votes. The Votes table stores a record that contains the Id of a user.
As a simple example, let's say my Users table has the following fields:
UserId, Name, Age, Gender
And my Votes table has:
UserId, DateCreated
What I want to do is select the top 10 users that have the highest votes.
How can I do this?
Thanks
Context.Users.OrderByDescending(x => x.Votes.Count()).Take(10)
Assuming you've got navigation properties set up between your tables, you could do this:
var results = db.Users.OrderByDescending(u => u.Votes.Count()).Take(10);
This will find the top 10 users with the greatest number of votes.
If you don't have foreign keys/property mapped:
var query = (from u in db.Users
join v in (
from v in db.Votes
group v by v.UserId into grp
select new {
UserId = grp.Key,
Count = grp.Count()
}) on u.Id equals v.UserId into l_vset
from l_v in l_vset.DefaultIfEmpty()
orderby l_v == null ? 0 : l_v.Count descending
select new {
User = u,
Votes = l_v == null ? 0 : l_v.Count
}).Take(10);

How to convert SQL Left Join query to Linq to Entity in C#?

I have a Table: Material(ID,Name,MAterialParentID)
SELECT c1.ID,c1.Name as ParentName,c2.id,c2.Name
FROM Material c1 Left JOIN Material c2
ON c1.ID = c2.MaterialParentID
ID ParentName id Name
1 Aluminium 2 Cavity
1 Aluminium 3 Copper
1 Aluminium 4 Flooring
2 Cavity NULL NULL
3 Copper NULL NULL
4 Flooring NULL NULL
5 Glass NULL NULL
I want to convert the above SQL Query to Linq Query using Liq to Entities.
Help Appreciated!
if the table is only for reading you could simply create a view and then when using reverse engineering make sure you have views imported.
or if you did want this done in LINQ here is the MSDN example
var innerJoinQuery =
from cust in customers
join dist in distributors on cust.City equals dist.City
select new { CustomerName = cust.Name, DistributorName = dist.Name };
this is how yours would look
var Material = from M in db.Materials
join M2 in db.Materials on M.ID equals M2.MaterialParentID
select new {ParentID = M.ID, ParentName = M.Name, M2.ID, M2.Name };
i have edited my post above as you can see i have included the ParentID to make all columns unique
For this kind of problem linqpad is your friend.
I'd suggest something like:
var materials = (from m in context.Material
let moreMaterials = (from m2 in context.Material where m2.id == m.id select m2).FirstOrDefault()
select m).ToList();
But you can use linqpad to customise to your query requirements.

Getting objects using LINQ and stored procedure

I have a stored procedure that is returning data in this format:
EmployeeID | DepartmentID
---------------------
1 | 1
2 | 1
3 | 2
4 | 4
5 | 4
I'm getting the results like so:
List<spResult> results = DataContext.sp().ToList();
I'd like to get a list of Employees for a certain Department, based on the data returned from the stored procedure. Something like:
int departmentId = 1;
List<Employee> employees = (from e in DataContext.Employees
//where...
select e).ToList();
How do I format my where clause to get the EmployeeIDs from the result set that have the given DepartmentID?
How about:
List<spResult> results = DataContext.sp().ToList();
int departmentId = 1;
var departmentEmployees = from de in results
where de.DepartmentId == departmentId
select de.EmployeeID;
List<Employee> employees = (from e in DataContext.Employees
where departmentEmployees.Contains(e.ID)
select e).ToList();
You could get a subset of keys:
var empKeys = results.Where(i => i.DepartmentID = departmentID);
And then use this list in the query like:
List<Employee> employees = (from e in DataContext.Employees
where empKeys.Contains(e.EmployeeID)
select h).ToList();
HTH.
You should also be able to do something like this:
List<Employee> employees = DataContext.Employees.Where(e => empKeys.Contains(e.EmployeeID)).ToList()

Categories

Resources