Linq Left Join table with sub set of another table - c#

Consider the query
var query = from A in _context.A.AsExpandable().Where(condition)
let B = _context.B
.Where(a=> a.Id == B.Id)
.Select(x=> new
{
x.Id,
x.Name
}).ToList()
select new {A.Id, B }
var res = query.ToList()
The Generated T-SQL similar to
SELECT [t0].Id, [s].Id, [s].Name
FROM A AS[t0]
LEFT JOIN [B] AS [s] ON [t0].[Id] = [s].[Id]
I Was wondering instead of joining the whole table is possible/better to join a subset(may be a inner join which just fetches two column instead of all the columns) of the table to improve performance?.
What it basically does it Left joins table A with table B, I'm trying to join the table A with the subset of table B (Id, Name) instead of selecting all the column.
Is it possible to achieve this??
would it improve the performance or degrade the performance?

Related

Entity Framework Core: join two tables and get the properties I want using LINQ

I have two related tables. Then I use LINQ to query Data.
this is my code
var items = await (from a in queryable
join b in _context.TUserGrant on a.UserNo equals b.UserNo
join c in _context.TProviderInfo on a.ProviderNo equals c.ProviderNo
orderby a.BillNo
select new
{
a.BillNo,
a.NotificeBillNo,
makeName = b.UserName,
a.MakeDate,
a.ProviderNo,
c.ProviderName,
a.CheckTime,
a.CheckAddress,
a.CheckName,
a.StatusTitle,
}).ToListAsync();
My problem is that I need all the columns of the first table, which is all the values of A.
I also need some columns from table B.
I wonder if there is an easy way to get these columns.
Instead of setting them one by one in the SELECT method.
You can try this
var items = await (from a in queryable
join b in _context.TUserGrant on a.UserNo equals b.UserNo
join c in _context.TProviderInfo on a.ProviderNo equals c.ProviderNo
orderby a.BillNo
select new
{
tabA = a,
makeName = b.UserName
}).ToListAsync();

LINQ - query on query results (some complex one)

Need some help in writing LINQ from the following SQL.
The main problem is double grouping.
I'm stacked in the second grouping
group by s.[e-year], s.[e-month]
Don't know how to implement.
Thanks a lot.
select s.[e-year], s.[e-month], count(s.projectid) 'projects entranced',
---------------------------------------------
(select count(subquery.CustomerTypeID) from
(select count(ap.ProjectID) as 'count', c.CustomerTypeID FROM Logging_ProjectsEntrances] pe
inner join users u on pe.userid = u.userid
inner join Companies c on u.CompanyId = c.CompanyID
inner join AssignedProjects up on pe.ProjectID = up.ProjectID
inner join Projects p on up.ProjectID = p.ProjectID
where ap.ProductID = 1 and year(pe.EntranceDate) = s.[e-year] and MONTH(pe.entrancedate) = s.[e-month] and c.CustomerTypeID = 2
group by ap.ProjectID, c.CustomerTypeID) subquery
group by subquery.CustomerTypeID
)
--------------------------------------------
from
(
select YEAR(pe.EntranceDate) as 'e-year', MONTH(pe.EntranceDate) as 'e-month', up.ProjectID as 'projectid'
FROM Logging_ProjectsEntrances pe
inner join AssignedProjects ap on pe.ProjectID = ap.ProjectID
inner join Projects p on ap.ProjectID = p.ProjectID
where ap.ProductID = 1
group by year(pe.EntranceDate), month(pe.EntranceDate), ap.ProjectID
) as s
group by s.[e-year], s.[e-month]
order by s.[e-year] desc , s.[e-month] desc
For translating SQL to LINQ query comprehension:
Translate FROM subselects as separately declared variables.
Translate each clause in LINQ clause order, translating monadic operators (DISTINCT, TOP, etc) into functions applied to the whole LINQ query.
Use table aliases as range variables. Use column aliases as anonymous type field names.
Use anonymous types (new { ... }) for multiple columns.
Left Join is simulated by using a into join_variable and doing another from from the join variable followed by .DefaultIfEmpty().
Replace COALESCE with the conditional operator and a null test.
Translate IN to .Contains() and NOT IN to !...Contains()
SELECT * must be replaced with select range_variable or for joins, an anonymous object containing all the range variables.
SELECT fields must be replaced with select new { ... } creating an anonymous object with all the desired fields or expressions.
Proper FULL OUTER JOIN must be handled with an extension method.
Note: Your SQL query is using a SQL trick (SELECT x ... GROUP BY x) to perform the equivalent of a DISTINCT, which should be used as it expresses the intent more clearly.
So, for your SQL query:
var subq = (from pe in projectsEntrances
join ap in assignedProjects on pe.ProjectID equals ap.ProjectID
join p in projects on ap.ProjectID equals p.ProjectID
where ap.ProductID == 1
select new { e_year = pe.EntranceDate.Year, e_month = pe.EntranceDate.Month, ap.ProjectID }).Distinct();
var ans = from s in subq
group s by new { s.e_year, s.e_month } into sg
orderby sg.Key.e_year descending, sg.Key.e_month descending
select new { sg.Key.e_year, sg.Key.e_month, ProjectsEntranced = sg.Count() };

Entity Framework: How to perform left join with EF and LINQ among multiple tables

basically i have 3 tables and those are user,colors and usercolor
tables info
User Tables has fields like -> UserID, UserName
Color Tables has fields like -> ColorID, ColorName
UserColor Tables has fields like -> UserID, ColorID
i have corresponding dbset classes in my code.
now see the below query where left join is performed among 3 tables in sql and tell me how to write the same equivalent query with EF and LINQ.
select c.ColorID
, c.ColorName
, IsSelected = case when uc.ColorID is null then 0 else 1 end
from dbo.Colors c
left join dbo.UserColor uc on uc.ColorID = c.ColorID and uc.UserID = 1 --leave this in the join or it becomes an inner join
left join dbo.Users u on u.UserID = uc.UserID
You can try as shown below.
var result = from c in dbo.Colors
join uc in dbo.UserColor on (uc.ColorID = c.ColorID and uc.UserID = 1) into UserColor
from q in UserColor.DefaultIfEmpty() join u in dbo.Users
on q.UserID equals u.UserID into Users
from l in Users.DefaultIfEmpty()
select new
{
ColorID = c.ColorID,
ColorName = c.ColorName,
IsSelected = uc.ColorID == null ? 0 : 1
};
You can read more about Left Outer Join in LINQ to Entities

Need some help in lambda expression from SQL query

I have this SQL query:
select
SubCaseNumber, MySaleries.WorkDate, stscreator.name, Status, SheetId
from
(select *
from
(select distinct
Sheets.SheetID SheetID, ShtInfos.SheetInfoID SheetInfoID,
ShtInfos.Creator_Id STSCreatorID, ShtUsers.User_ID STSFitterID,
Sheets.Status, ShtInfos.workdate, ShtInfos.SubCase_SubCaseId
from [Sheets]
left join [SheetInfoes] ShtInfos on sheets.SheetInfo_SheetInfoId = ShtInfos.SheetInfoId
left join [SheetUsers] ShtUsers on Sheets.SheetID = ShtUsers.Sheet_SheetID) AllSheets
where
(stsfitterID = '08153661-6520-4435-81e6-6064084db74d'
or stscreatorid = '08153661-6520-4435-81e6-6064084db74d')
and Status = 1) MySaleries
join
[SubCases] SubCases on SubCase_SubCaseId = SubCases.SubCaseId
join
[AspNetUsers] STSCreator on STSCreator.Id = MySaleries.STSCreatorID;
(returning 8 rows - correct)
And I have written the following Linq query to implement the SQL in Linq:
from Sht in Sheets
join SI in SheetInfoes on Sht.SheetInfo_SheetInfoId equals SI.SheetInfoId
join SC in SubCases on SI.SubCase_SubCaseId equals SC.SubCaseId
join ShtUsr in SheetUsers on Sht.SheetId equals ShtUsr.Sheet_SheetId
join STSUsr in AspNetUsers on SI.Creator_Id equals STSUsr.Id
where (ShtUsr.User_Id == "08153661-6520-4435-81e6-6064084db74d" || SI.Creator_Id == "08153661-6520-4435-81e6-6064084db74d") && SI.Status == 1
select new {SC.SubCaseNumber, SI.WorkDate, STSUsr.Name, Sht.Status, Sht.SheetId}
Returning 50 rows - should bee 8 rows too.
I have following tables:
[SheetInfoes], [Sheets], [SubCases], [AspNetUsers], [SheetUsers]
What am I doing wrong?
Your join conditions in the SQL you posted are LEFT joins. Your joins in the code are just joins without any filtering.
Example:
from maintable in Repo.T_Whatever
from xxx in Repo.T_ANY_TABLE.Where(join condition).DefaultIfEmpty()
I'd set it up something like this:
var query = (
from Sht in Sheets
from SheetInfoes
.where(x => x.SheetInfoId == Sht.SheetInfo_SheetInfoId)
.DefaultIfEmpty() // <== left join
from ShtUsr in SheetUsers
.where(x => x.SheetId == ShtUsr.Sheet_SheetId)
.DefaultIfEmpty() // <== left join
//You'll need to finish it
Take a look at this for a more info: Left Outer Joins

Convert inner join sql query to linq

I have a sql query which is to be converted to Linq
Select b.title
from TableA as a
inner join TableB as b
on a.Email=b.Email
where a.Title<>b.Title
the query which i have tried is
var query =from s in TableA
join r in TableB
on r.Email equals s.Email
but not able to replicate the where clause which may include many columns
My requirement is i need to compare the 2 tables on a primary key column and then get the other column values which do not match
You need a "select" at the end of the query, and you need to get the inputs in the right order:
var query = from s in TableA
join r in TableB on s.Email equals r.Email
where s.Title != r.Title
select s.Title;
For multiple columns, use an anonymous type:
var query = from s in TableA
join r in TableB
on new { s.Email, s.Foo } equals new { r.Email, r.Foo }
where s.Title != r.Title
select s.Title;

Categories