how to use lambda with leftjoin and isnull check - c#

I am close but no cigar. In SQL I can use an ISNULL in my where clause but I can't seem to get it to pass in linq.
var q3 =(
from Prin in HR
.Where(Prin => (Prin.JobName == "Pricipal-Elementary") &&
(ASup =>((String.Compare(ASup.UnitName,null) >=0)&&
(String.Compare(ASup.UnitName ,"%Learning%"))
))
)
//WHERE Prin.JobName = 'Principal-Elementary'
//AND ISNULL(ASup.UnitName,'') LIKE '%Learning%'
//ORDER BY SchoolName
from ASup in HR
.Where(ASup => ASup.ADAccount == Prin.ChiefADAccount)
.DefaultIfEmpty()
from Sch in UnitToSchools
.Where(Sch => Sch.UnitCode == Prin.UnitCode)
.DefaultIfEmpty()
select new
{
SchoolName = Prin.UnitName
,SchoolId = Sch.SchoolDetailFCSId
,PrincipalID = Prin.ADAccount
,LComm = ASup.UnitName
,AreaSupId = Prin.ChiefADAccount
}
);
var xyz = (q3).ToList();
//Below is the correct query in SQL
SELECT Prin.UnitName AS SchoolName
, Sch.SchoolDetailFCSId AS SchoolId
, Prin.ADAccount AS PrincipalID
, ASup.UnitName AS LComm
, Prin.ChiefADAccount AS AreaSupID
FROM IP_F.dbo.HR Prin
LEFT OUTER JOIN IP_F.dbo.HR ASup
ON ASup.ADAccount = Prin.ChiefADAccount
LEFT OUTER JOIN IP_F.dbo.UnitToSchool Sch
ON Sch.UnitCode = Prin.UnitCode
WHERE Prin.JobName = 'Principal-Elementary'
AND ISNULL(ASup.UnitName,'') LIKE '%Learning%'
ORDER BY SchoolName
Any help would be appreciated. Apparently I can't use String.Compare on a lambda. So I am stuck...
Thanks in Advance.

This part of your query:
ISNULL(ASup.UnitName,'') LIKE '%Learning%'
would be written in LINQ as
(ASup.UnitName ?? '').Contains("Learning")

Have your tried something like?
(String.IsNullOrEmty(ASup.UnitName) ? string.Empty : ASup.UnitName).Contains("Learning")

Related

How to create a left join instead of inner join?

I have an SQL query which i am converting to Linq and i want to use Left Join instead of Inner Join.
I have tried DefaultIfEmpty() method but i haven't had any luck.
The Sql query:
SELECT t0.*, t1.* FROM entity AS t0
LEFT JOIN migration_logs AS t1 ON (CAST(t0.id AS CHAR) = t1.ObjectId and 'SASParty' = t1.ObjectType)
where t1.status is null || t1.Status <> '1' ORDER BY t0.id LIMIT 0, 10;
The Linq Query:
Entities
.Join(Migration_logs,
e => new { id = e.Id.ToString(), ObjectType = "SASParty" },
mlog => new { id = mlog.ObjectId, mlog.ObjectType },
(e, mlog) => new {e,mlog})
.Where(result => result.mlog.Status == null || result.mlog.Status != "1").DefaultIfEmpty().ToList()
I am using linqpad and when i execute the linq query it generates the following sql query:
SELECT t0.*
FROM entity AS t0
INNER JOIN migration_logs AS t1
ON ((CAST(t0.id AS CHAR) = t1.ObjectId) AND (#p0 = t1.ObjectType))
WHERE ((t1.Status IS NULL) OR (t1.Status <> #p1))
Some minor differences in the original query and generated sql query are there but i hope the problem statement is clear.
Any help would be appreciated.
I was able to find a solution with the linq to sql query and using into clause.
(from e in Entities
join mlog in Migration_logs
on new { id = e.Id.ToString(), ObjectType = "SASParty" }
equals new { id = mlog.ObjectId, mlog.ObjectType }
into results
from r in results.DefaultIfEmpty()
where r.Status == null || r.Status != "1"
select new
{
e
})
you want to perform the .DefaultIfEmpty() method on the quantity that you want to perform a left join onto. maybe this code snippet helps you
from e in Entities
join ml in Migration_lpgs on new { id=e.Id.ToString(), ObjectType="SASParty" } equals new { id=ml.Id.ToString(), mlog.ObjectType } into j
from e in j.DefaultIfEmpty()
where ml.Status == null || ml.Status != "1"
select e

How do I write SELECT FROM myTable WHERE id = (SELECT) in Linq?

How can I rewrite this SQL query in LINQ with a lambda expression?
SELECT
CO.*
FROM
COMPANY CO
WHERE
CO.ID = '5'
AND CO.ID <> (SELECT COMPANY_ID
FROM dbo.EMPLOYEE
WHERE USERNAME = 'ADMIN')
I tried the following code I think it is correct, but it is not working:
var obj1 = db.COMPANies
.Where(co => co.ID != co.EMPLOYEEs.SingleOrDefault(em => em.USERNAME == userName).COMPANY_ID && co.ID == iID);
Can you please help me?
Can I use
co.EMPLOYEEs.SingleOrDefault(em => em.USERNAME == userName).COMPANY_ID
inside the db.COMPANies.Where ??
I have read the question in: How do I write SELECT FROM myTable WHERE id = (SELECT) in Linq?
but it not help me.
EDIT :
Image table structure, Click here
Sorry for my bad english. Thanks!
I hope that you have objects of COMPANY table and EMPLOYEE table which will be having the data. On those objects, you can fire the below LINQ to achieve your results.
COMPANY.Select(x => x.Id == 5 && x.Id != EMPLOYEE.Where(z => z.USERNAME == "ADMIN").Select(g => g.COMPANY_ID).FirstOrDefault());
Don't forget to add using System.Linq;
Using lambda expression, you can try this
var comapaniesWhereUserIsAdmin = from e in db.EMPLOYEEs
where e.username='Admin'
select e.CompanyId;
var result = from c in db.Companies
where c.ID == iID && !comapaniesWhereUserIsAdmin.Contains(c.ID)
select c;

Convert multiple PARTITION BY to LINQ

EF Core does not have a SqlQuery() method yet (epic fail) so I have no way to run a query/stored proc on my database to get "summary" data. Here is a summary query I have with multiple PARTITION BYs that I need to convert to LINQ:
SELECT
s.Name,
SUM(CASE WHEN pc.WorkflowStateId <> 99 THEN 1 ELSE 0 END)
OVER (PARTITION BY s.SiteId) 'RegisteredCount',
SUM(CASE WHEN pc.WorkflowStateId = 99 THEN 1 ELSE 0 END)
OVER (PARTITION BY s.SiteId) 'ScreenFailedCount'
FROM Sites s
JOIN Patients p ON p.SiteId = s.SiteId
JOIN PatientCycles pc ON pc.PatientId = p.PatientId
Sites, Patients, and PatientCycles are DbSets.
How can I convert this to a C# LINQ query?
UPDATE
This is the solution I came up with:
var summaries = from site in context.Sites
let registered = (from pc in context.PatientCycles
where site.SiteId == pc.Patient.SiteId && pc.WorkflowStateId != WorkflowStateType.Terminated
select pc).Count()
let terminated = (from pc in context.PatientCycles
where site.SiteId == pc.Patient.SiteId && pc.WorkflowStateId == WorkflowStateType.Terminated
select pc).Count()
select new SiteSummary { Site = site, RegisteredCount = registered, ScreenFailedCount = terminated };
Well an alternative in Linq would be something like this:
var query= from s in context.Sites
join p in context.Patiens on s.SiteId equals p.SiteId
join pc in context.PatientCycles on p.PatiendId equals p.PatiendId
group pc.WorkflowStateId by new{s.SiteId,s.Name} into g
select new {Name=g.Key.Name,
RegisteredCount=g.Sum(e=>e!=99?1:0),
ScreenFailedCount=g.Sum(e=>e==99?1:0)
}
Update
To avoid that kind of problem use nav. properties:
var query= from s in context.Sites
select t new SiteSummary
{
SiteId = s.SiteId,
Name = s.Name,
Code = s.Code,
RegisteredCount =s.Patiens.SelectMany(e=>e.PatientCycles.Select(y=>y.WorkflowStateId ))
.Sum(x => x!= WorkflowStateType.Terminated ? 1 : 0),
ScreenFailedCount = s.Patiens.SelectMany(e=>e.PatientCycles.Select(y=>y.WorkflowStateId ))
.Sum(x => x== WorkflowStateType.Terminated ? 1 : 0)
};
Also I suggest to initialize the collection navigation properties in entity constructors:
public class Sites
{
//...
public virtual ICollection<Patient> Patients{get;set;}
public Sites()
{
Patients=new List<Patient>();
}
}

FIiter Out the Linq Query

I have List List courseTakenList.i want to filter out the Status which are in Completed,Dropped,Current,Schudeled. Here is the code sample.
courseTakenList = (from courseTaken in courseTakenList
select new Course
{
Status = "Scheduled"?"COMPLETE"?"Dropped"? "Current"
}).ToList();
You could do it even more concise
var statuslist= {"Completed","Dropped","Current","Schudeled"};
var courses = courseTakenList.Where(courseTaken =>
statuslist.Contains(courseTaken.Status);
Linq In query like this will resolve your issue
var statuslist= {"Completed","Dropped","Current","Schudeled"};
var query = from courseTaken in courseTakenList
where statuslist.Contains( courseTaken .Status )
select courseTaken ;
Note : change select clause as you want

Linq to Entities Left Outer Join with different types

I've probably spent 40 hours on this problem so far, I've tried every solution on this site and on google, and I still can't make this work.
I need to left join a table to the results of a previous query, stored in a var. The joining field is a varchar in the table queried for the result in the var, and a bigint (long) in the table being joined. Here is the current attempt, which tells me "Object reference not set to an instance of an object." All Entities errors seem like nonsense and lies to me, I assume it's trying to tell me nothing matched, but who knows.
List<reportUser> ru = leaders
.GroupJoin(db.sweeps,
a => a.FBID.ToString(),
s => s.userFBID.First().ToString(),
(a, matching) => new reportUser
{
FBID = a.FBID,
CurrentPoints = a.CurrentPoints,
Name = matching.FirstOrDefault().Name,
Email = matching.FirstOrDefault().email
}
?? new reportUser
{
FBID = 0,
CurrentPoints = 0,
Name = "",
Email = ""
})
.Select(a => a)
.ToList();
Here's the SQL requested below. I've included the SQL to build the Leaders object as well, all the above is really meant to represent is the last line, which is simply a left join.
select s.name, s.email, b.score, c.score overall
from (
select a.userfbid, sum(a.pointvalue) score
from (
select userfbid, pointvalue
from l
left join qa on qa.id = l.qaid
left join q on q.id = qa.qid
left join qz on qz.id = q.qzid
where qa.pointvalue > 0 and qz.cid = 12
union all
select fbid userfbid, pointvalue
from bn
where date >= '5/9/2011 04:00' and
date <= '5/16/2011 04:00'
) a
group by a.userfbid
) b
left join (
select a.userfbid, sum(a.pointvalue) score
from (
select userfbid, pointvalue
from l
left join qa on qa.id = l.qaid
left join q on q.id = qa.qid
left join qz on qz.id = q.qzid
where qa.pointvalue > 0
union all
select fbid userfbid, pointvalue
from bn
) a
group by a.userfbid
) c on c.userfbid=b.userfbid
left join s on s.userfbid=b.userfbid
order by score desc
I'm assuming that in your database s.userFBID.First() is never null?
If that's right, then your problem could be in the FirstOrDefault().Name type statements - when FirstOrDefault() evaluates to null then obviously you will get a nullreferenceexception :/
To get around this, try something like:
List<reportUser> ru = leaders
.GroupJoin(db.sweeps,
a => a.FBID.ToString(),
s => s.userFBID.First().ToString(),
(a, matching) =>
{
var match = matching.FirstOrDefault();
return match != null ?
new reportUser
{
FBID = a.FBID,
CurrentPoints = a.CurrentPoints,
Name = match.Name,
Email = match.email
}
: new reportUser
{
FBID = 0, // a.FBID ?
CurrentPoints = 0, // a.CurrentPoints ?
Name = "",
Email = ""
}})
.Select(a => a)
.ToList();
However, I find it a bit hard to do this without seeing the structure of the database... or some sample data
Once you've got something working... then I highly recommend you try breaking this down into something more easily understandable - I'm really not sure what's going on here!
Here's a simple left outer join for you:
var query = from l leaders
join s in db.sweeps on l.FBID equals s.userFBID.First() into joined
from j in joined.FirstOrDefault()
select new reportUser
{
FBID = l.FBID,
CurrentPoints = l.CurrentPoints,
Name = j == null ? string.Empty : j.Name,
Email = j == null ? string.Empty : j.email
}
If this isn't quite what you are looking for... maybe try posting the SQL for what you actually want.

Categories

Resources