Linq to SQL query with COALESCE in where clause - entity-framework

I am trying to convert the following sql query in to linq to sql (for entity framework)
select A.*, B.* from TABLE1 A
left join TABLE2 B
on A.LocationLoadPositionId = B.FkLocationLoadPositionId
where COALESCE(B.UploadStatus,0) = 0
So far I've got it to this far:
var positions = (from a in dbContext.TABLE1 join b in dbContext.TABLE2
on a.LocationLoadPositionId equals b.FkLocationLoadPositionId into c from d in c.DefaultIfEmpty()
where d.UploadStatus == false select new { a, d }).ToList();
The above linq query doens't seem to be working correctly because of my where condition... I am getting different result set for the two queries above... what am i missing here?...

Try this:
var positions = (from a in dbContext.TABLE1 join b in dbContext.TABLE2
on a.LocationLoadPositionId equals b.FkLocationLoadPositionId into c from d in c.DefaultIfEmpty()
where d.UploadStatus == false || d == null select new { a, d }).ToList();

Somethings like..
var positions = (from a in dbContext.TABLE1
join b in dbContext.TABLE2
on a.LocationLoadPositionId equals b.FkLocationLoadPositionId into c
let x = d.UploadStatus == 0 //<--- COALESCE
from d in c.DefaultIfEmpty()
where x == true).ToList();
return query.ToList();

Related

Linq Limit/Group by Id when joining IQueryables

I have a list of ids, that I then have multiple IQueryables that at the end I am joining to return my results. However some of these queries could have multiple records for that particular ID and I only need 1 record per ID from my set of x IDs. For example there could be 1 Name record, 3 Addresses, 2 Emails, 4 Phones for a single ID, but I only need 1 of each, does not matter which if multiple exist.
var clientNames = (
from n in db.Names
join cnl in db.ClientNameLinks on n.name_id equals cnl.name_id
where request.Ids.Contains(cnl.client_id)
&& n.name_id > 0
&& n.nametype_id != null
select new
{
n.display_name,
cnl.client_id
});
var clientAddresses = (
from a in db.Addresses
join cal in db.ClientAddressLinks on a.address_id equals cal.address_id
where request.Ids.Contains(cal.client_id)
&& a.address_id > 0
select new {
a.display_address,
cal.client_id
});
var clientEmails = (
from e in db.Emails
join cel in db.ClientEmailLinks on e.email_id equals cel.email_id
where request.Ids.Contains(cel.client_id)
&& e.email_id > 0
select new {
e.email_address,
cel.client_id
});
var clientPhones = (
from p in db.Phones
join cpl in db.ClientPhoneLinks on p.phone_id equals cpl.phone_id
where request.Ids.Contains(cpl.client_id)
&& p.phone_id > 0
select new {
p.phone_num,
cpl.client_id
});
var rows = await (
from n in clientNames
join a in clientAddresses on n.client_id equals a.client_id into n_a
from na in n_a.DefaultIfEmpty() //LEFT JOIN
join e in clientEmails on n.client_id equals e.client_id into n_e
from ne in n_e.DefaultIfEmpty() //LEFT JOIN
join ph in clientPhones on n.client_id equals ph.client_id into n_p
from np in n_p.DefaultIfEmpty() //LEFT JOIN
select new PiiDiamondClient
{
ClientId = n.client_id,
DisplayName = n.display_name,
DisplayAddress = na.display_address,
EmailAddress = ne.email_address,
PhoneExtension = np.phone_ext,
PhoneNumber = np.phone_num
}).Distinct().ToListAsync();
return rows.OrderBy(x => x.ClientId).ToList();
Your last query can be rewritten in the following way. It will exactly get one record from JOIN which can multiply result set.
var query =
from n in clientNames
from a in clientAddresses.Where(a => n.client_id == a.client_id)
.Take(1).DefaultIfEmpty() //OUTER APPLY or LEFT JOIN on ROW_NUMBER query
from e in clientEmails.Where(e => n.client_id == e.client_id)
.Take(1).DefaultIfEmpty() //OUTER APPLY or LEFT JOIN on ROW_NUMBER query
from ph in clientPhones.Where(ph => n.client_id == ph.client_id)
.Take(1).DefaultIfEmpty() //OUTER APPLY or LEFT JOIN on ROW_NUMBER query
select new PiiDiamondClient
{
ClientId = n.client_id,
DisplayName = n.display_name,
DisplayAddress = a.display_address,
EmailAddress = e.email_address,
PhoneExtension = ph.phone_ext,
PhoneNumber = ph.phone_num
};

Filter entities with a field from another entity in linq query c#

I wanna join some tables in linq query. The problem is that I can not filter one of entities with field of another entity. In the below code b.createDate is not defiend, how can I do this query in linq?
From a in context.A
Join b in context.B
On a.Id equals b.AId
Join c in context.C.where(x =>
x.createDate >= b.createDate)
On b.Id equals c.BId into g
From result in
g.DefaultIfEmpty()
Select result
You have to use from instead of join in this case. As documented: Collection selector references outer in a non-where case
var query =
from a in context.A
join b in context.B on a.Id equals b.AId
from c in context.C
.Where(x => x.BId == b.Id && x.createDate >= b.createDate)
.DefaultIfEmpty()
select c;

C# - Which is syntax in LINQ to EF for this query?

I have two table
Teachers(**int IDT**, int mat, String name ) and Courses(String name, **int IDT**). IDT is FKey in Courses and PKey in Teachers.
Then the teacher cant are in more that 3 courses. My query work fine in sql. My question is, 'How write this in LINQ to EF'?
select p.name, p.mat, p.IDT, count(c.IDT) from Teachers p
left join courses c on c.IDT = p.IDT
group by p.name, p.mat, p.IDT
having count(c.IDT) <3
You can try as shown below.
from p in context.Teachers
join c in context.courses on c.IDT equals p.IDT into j1
from j2 in j1.DefaultIfEmpty()
group j2 by new { p.name, p.mat, p.IDT } into grouped
let theCount = grouped.Sum(e => e != null ? 1 : 0)
where theCount < 3
select new { Name = grouped.Key.name, Mat= grouped.Key.mat,
Idt=grouped.Key.IDT,Count = theCount }

LINQ join query returning null

I've three tables.
Table A
id name des table2 table3
1 xyz TableA_des1 null 1
2 abc TableA_des2 1 2
3 hgd TableA_des2 2 3
Table B
id name des Active
1 xyz TableB_des1 1
2 abc TableB_des2 1
3 hgd TableB_des2 1
Table C
id name des Active
1 xyz TableC_des1 1
2 abc TableC_des2 1
3 hgd TableC_des2 1
LINQ Query
var res = (from a in TableA
where id = 1
join b in TableB on a.table2 equals b.id into ab
from bdata in ab.DefaultIfEmpty()
where bdata.Active = true
join c in TableC on a.table3 equals c.id into ac
from cdata in ac.DefaultIfEmpty()
where cdata.Active = true
select new { data1 = a.name, data2 = bdata?? string.Empty, data3 = cdata?? string.Empty})
The about query is giving null. On debugging variable res has null.
You should avoid putting where conditions on range variables coming from the right side of a left outer join, because doing so effectively turns them into inner join.
Instead, you should either apply the right side filtering before the join:
from a in TableA
where id = 1
join b in TableB.Where(x => a.Active)
on a.table2 equals b.id
into ab
from bdata in ab.DefaultIfEmpty()
join c in TableC.Where(x => x.Active)
on a.table3 equals c.id
into ac
from cdata in ac.DefaultIfEmpty()
...
or include them in the join (when possible):
from a in TableA
where id = 1
join b in TableB
on new { id = a.table2, Active = true } equals new { b.id, b.Active }
into ab
from bdata in ab.DefaultIfEmpty()
join c in TableC
on new { id = a.table3, Active = true } equals new { c.id, c.Active }
into ac
from cdata in ac.DefaultIfEmpty()
...
In order to understand why is that, try to evaluate where bdata.Active == true when bdata is null (i.e. there is no matching record). Actually if this was LINQ to Objects, the above criteria will generate NullReferenceException. But LINQ to Entities can handle that w/o exceptions, since databases naturally support null values in queries for a columns which are normally non nullable. So the above simple evaluates to false, hence is filtering the resulting record and effectively removing the effect of a left outer join which by definition should return the left side record regardless of whether a matching right side record exists.
Which means that actually there is a third way (althought the first two options are preferable) - include an explicit null checks:
from a in TableA
where id = 1
join b in TableB
on a.table2 equals b.id
into ab
from bdata in ab.DefaultIfEmpty()
where bdata == null || bdata.Active
join c in TableC
on a.table3 equals c.id
into ac
from cdata in ac.DefaultIfEmpty()
where cdata == null || cdata.Active
...

NHibernate query help needed

Is it possible to convert the following query into ICriteria or LINQ, and if so, how?
SELECT Test.personid
FROM
(
SELECT r.PersonId AS personid, e.ActivityId
FROM Event e
INNER JOIN Registration r ON e.Id = r.EventId
WHERE e.ActivityId IN (1, 2)
GROUP BY r.PersonId, e.ActivityId
) AS Test
GROUP BY Test.personid
HAVING COUNT(Test.ActivityId) >= 2
var result = from r in session.Query<Registration>()
where r.Event.ActivityId == 1 || r.Event.ActivityId == 2
group r by r.Person into g
where g.Min(x => x.Event.ActivityId) != g.Max(x => x.Event.ActivityId)
select g.Key
the following states, take all Persons wich have different activityIds in there groups which is equivalent to
ActivityId == 1 || ActivityId == 2
Having Count(r.Event.ActivityId) >= 2