LEFT JOIN with OR condition in LINQ - c#

I need to write following T-SQL in LINQ:
SELECT T1.ID, T2.Name
FROM T1
LEFT JOIN T2 ON (T1.ID = I2.ID1 OR T1.ID = T2.ID2)
An OR-join would look like this in LINQ:
T1.Join(T2, t1=>new{}, t2=>new{}, (t1,t2)=>new{ID=t1.Id, t2=t2}).Where(o=>o.Id == o.t2.Id1 || o.Id==o.t2.Id2);
But that query is an INNER JOIN, not a LEFT JOIN.
Some kind of LEFT JOIN would look like this:
T1.GroupJoin(T2, t1 => t1.Id, t2 => t2.Id1, (t1, t2) => new { Id = t1.Id, Name1 = t2.Select(t => t.Name) }).DefaultIfEmpty()
.GroupJoin(T2, o => o.Id, t2 => t2.Id2, (i, j) => new { Id = i.Id, Name1 = i.Name1, Name2 = j.Select(t => t.Name) }).DefaultIfEmpty();
This query produces correct results, but makes 2 joins instead of 1. Or is it really equivalent to original T-SQL?
Does anybody know how to rewrite this query better?

This answer from a similar question gives us an easy way to write LEFT JOINs:
https://stackoverflow.com/a/4739738/1869660
var query = from t1 in T1
from t2 in T2.Where(tt2 => (t1.ID == tt2.ID1) || (t1.ID = tt2.ID2))
.DefaultIfEmpty()
select new { t1.ID, t2.Name }

To solve this with single linq, try using cross join
var results = (from a in test1
from b in test2
where a.ID == b.ID1 || a.ID == b.ID2
select new {x = a.ID, y = b.Name});

var LeftJoin = from emp in ListOfEmployees
join dept in ListOfDepartment
on emp.DeptID equals dept.ID into JoinedEmpDept
from dept in JoinedEmpDept.DefaultIfEmpty()
select new
{
EmployeeName = emp.Name,
DepartmentName = dept != null ? dept.Name : null
};

Related

How to rewrite sql query to linq

I'm trying to rewrite sql query to linq but can't do it myself.
The most problem for me is to get I,II and III aggregated values.
Sql query:
select o.Name,t.TypeID, SUM(e.I),SUM(e.II),SUM(e.III) from Expenditure e
join Finance f on f.FinanceId = e.FinanceId
join FinanceYear fy on fy.FinanceYearId = f.FinanceYearId and fy.StatusId = 1
join Project p on p.ProjectId = fy.ProjectId
join Organization o on o.OrganizationId = p.OrganizationId
join Type t on t.TypeID = p.TypeID
where fy.Year = 2018
group by o.Name,s.TypeID
and what I have done so far is:
var x = (from e in _db.Expenditures
join f in _db.Finances on e.FinanceId equals f.FinanceId
join fy in _db.FinanceYears on f.FinanceYearId equals fy.FinanceYearId and fy.StatusId = 1 // this does not work, cant join on multiple conditions?
join p in _db.Projects on fy.ProjectId equals p.ProjectId
join o in _db.Organizations on p.OrganizationId equals o.OrganizationId
join s in _db.Types on p.TypeId equals s.TypeId
group new { o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = ?,
II = ?,
III = ?,
}
);
Try something like this:
group new { e, o, s } by new { o.OrganizationId, s.TypeId }
into grp
select new AggModel
{
OrganizationId = grp.Key.OrganizationId,
TypeId = grp.Key.TypeId,
I = grp.Sum(a => a.e.I),
II = grp.Sum(a => a.e.II),
III = grp.Sum(a => a.e.III),
}
You'll need to adjust the right side of the lambda to navigate to the correct property.
You Need to use the Group by for aggregation methods.
Check the below link for more Knowledge.
How to use aggregate functions in linq with joins?

simplifying two queries into one with the same types linq

I have this code:
var commentData = from o in quack.BlogComments
join u in quack.AdminUsers
on o.UserId equals u.AdminUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
};
var commentData2 = from o in quack.BlogComments
join u in quack.RegularUsers
on o.UserId equals u.RegularUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
};
var l = commentData.ToList();
l.AddRange(commentData2);
As you can see above I am doing 2 different queries to the database and then adding them together to generate a single list to be used in the gridview.
What I want is to only use 1 query to the database and will result to two of those table combined.
How can I do it? is it possible with multiple joins?
You should use Concat:
var commentData = (from o in quack.BlogComments
join u in quack.AdminUsers
on o.UserId equals u.AdminUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
}).Concat(from o in quack.BlogComments
join u in quack.RegularUsers
on o.UserId equals u.RegularUserId
where blogid == o.BlogId
select new
{
o.Comment,
o.CommentDate,
u.FirstName,
u.LastName
});
var l = commentData.ToList();

SQL query to LINQ expression

I cannot make the following query into LINQ expression. Could you help me ?
SELECT Employee_Id_FK from TimeRegistrations as tr
JOIN Employees em ON tr.Employee_Id_FK = em.id
JOIN Managers m ON em.Manager_Id_FK = m.id
WHERE m.id = 4
This is what I have so far :
var result = from t in DB.TimeRegistrations
join Employees in DB.TimeRegistrations on t.Employee_Id_FK equals Employees.id
join Managers in DB.Managers on ..... ;
// Display results.
foreach (var r in result)
{
Console.WriteLine(r);
}
In case your db has foreign keys:
var result =from t1 in DB.TimeRegistrations
join t2 in t1.Employees
join t3 in t2.Managers
where t3.id == "4"
select t1
in case it does not:
var result =from t1 in DB.TimeRegistrations
join t2 in DB.Employees on t1.Employee_Id_FK equals t2.id
join t3 in DB.Managers on t2.id equals t3.Manager_Id_FK
where t3.id == "4"
select t1
However shorter way will be:
var result = DB.Managers.Find(4).Employees.SelectMany(e=>e.TimeRegistrations)
Or not that straight forward way:
var result = DB.TimeRegistrations
.Where(t=>t.Employees.Any(e=>e.Managers.Any(m=>m.id == 4)))

Linq To SQL - Having and Group By

I've this query below working fine. However I want to implement it using Linq.
select u.ID, u.NAME
from Task t
join BuildingUser bu ON bu.ID_BUILDING = t.ID_BUILDING
join [User] u ON u.ID = bu.ID_USER
where t.ID IN (2,9) AND u.ID != t.ID_USER
group by u.id, u.name
having count(bu.ID_BUILDING) = (SELECT COUNT(t2.ID_BUILDING) FROM Task t2 WHERE t2.ID IN (2,9))
I don't know how to Group and use Having clause at the same time.
You can try something like this:
var ids = new[] { 2, 9 };
var results =
from t in db.Tasks
join bu in db.BuildingUsers on t.ID_BUILDING equals bu.ID_BUILDING
group bu by bu.ID_BUILDING into bg
join u in db.Users on bg.Key equals u.ID
where ids.Contains(t.ID) && u.ID != t.ID_USER
group u by new { u.ID, u.NAME } into g
where bg.Count() == db.Tasks.Count(t2 => ids.Contains(t2.ID))
select g.Key;
Or if you have navigation properties set up correctly, you can try this:
var ids = new[] { 2, 9 };
var results =
from t in db.Tasks.Where(x => ids.Contains(x.ID))
from u in t.BuildingUsers.SelectMany(bu => bu.Users)
.Where(x => x.ID != t.ID_USER)
group u by new { u.ID, u.NAME } into g
where t.BuildingUsers.Count() == db.Tasks.Count(x => ids.Contains(x.ID))
select g.Key;

LINQ: Using INNER JOIN, Group and SUM

I am trying to perform the following SQL using LINQ and the closest I got was doing cross joins and sum calculations. I know there has to be a better way to write it so I am turning to the stack team for help.
SELECT T1.Column1, T1.Column2, SUM(T3.Column1) AS Amount
FROM T1
INNER JOIN T2
ON T1.T1ID = T2.T1ID
INNER JOIN T3
ON T2.T3ID = T3.T3ID
GROUP BY T1.Column1, T1.Column2
What I have been trying is the following LINQ code
var qTotal = from T2 in context.T2
from T3 in context.T3
where T3.T3ID == T3.T3ID
group T3 by T2.T1ID into gT2T3
from T1 in context.T1
where gT2T3.Key.Equals(T1.T1ID)
select new { T1.Column1,T1.Column2,Amount = gT2T3.Sum(t => t.Column1)};
I know there has to be a better way to write it, I just do not know how, any help would be great!
Try this:
var total = from T1 in context.T1
join T2 in context.T2 on T1.T2ID equals T2.T2ID
join T3 in context.T3 on T2.T3ID equals T3.T3ID
group T3 by new { T1.Column1, T1.Column2 } into g
select new {
Column1 = T1.Column1,
Column2 = T2.Column2,
Amount = g.Sum(t3 => t3.Column1)
};
For me (using 4.0), the following works.
var total = from T1 in context.T1
join T2 in context.T2 on T1.T2ID equals T2.T2ID
join T3 in context.T3 on T2.T3ID equals T3.T3ID
group T3 by new { T1.Column1, T1.Column2 } into g
select new {
Column1 = g.Key.Column1,
Column2 = g.Key.Column2,
Amount = g.Sum(t3 => t3.Column1)
};
Below code is working for me :
var credit = (from bm in BulkMessage
join sms in SMS on bm.BulkMessageId equals sms.BulkMessageId
where bm.ProfileId == pid && bm.IsActive == true
group sms by sms.SMSCredit into g
select new { SMSCredits = g.Sum(s => s.SMSCredit) }).FirstOrDefault();

Categories