How to use <> expression in Entity Framework - c#

We need to convert following query to Entity framework syntax based query but not fond any alternative for '<>' condition:
Query:
select (FirstName+' '+LastName) AS Name ,WorksNumber from [TSHumanResource]
join [TSUserProfile] on [TSUserProfile].[TSPersonID] = [TSHumanResource].[TSPersonID]
join [TSPerson] on [TSPerson].[TSPersonID] = [TSHumanResource].[TSPersonID]
where [TSUserProfile].[TSUserStatusID] = 1
and [EmployeeReference] <> ' ' and [MMSUserID] is not null order by [WorksNumber] asc
Here's what I was tring:
(from HR in oDB.TSHumanResources
join UP in oDB.TSUserProfiles on HR.TSPersonID equals UP.TSPersonID
join P in oDB.TSPersons on HR.TSPersonID equals P.TSPersonID
where UP.TSUserStatusID == 1 && HR.EmployeeReference <>
select new
{
ID = e.TSPersonID ,
ID = e.TID,
}).Take(10);

The SQL Server operator <> means not equal. In c#, the not equal operator is written like this: !=.
You have another problem in your linq query - you are currently doing an inner join instead of a left join.
A left join in LINQ is a bit cumbersome comparing to a left join in SQL - it has to go through a group join first. Your query should look more like this:
from hr in TSHumanResource
join up in TSUserProfile on hr.TSPersonID equals up.TSPersonID into upgroup
from upg in upgroup.DefaultIfEmpty()
join p in TSPerson on upg.TSPersonID equals p.TSPersonID into pgroup
from puphr in pgroup.DefaultIfEmpty()
where up.TSUserStatusID = 1
&& HR.EmployeeReference != " " // Assuming you want it different than a single space
// Other conditions here - I don't know where MMSUserID belongs to
order by hr.WorksNumber // just guessing here - I don't know if it's from hr

Related

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() };

convert SQL to LINQ not working

I want to convert this SQL code to LINQ. Here is my SQL code:
SELECT Rooms.RoomName AS RoomNo, Beds.BedName AS Beds, Rooms.RoomType, ISNULL(CheckIn.CheckIntatus,'') AS Status
FROM CheckIn
INNER JOIN GuestBeds ON CheckIn.GuestBedId = GuestBeds.Id
AND (CheckIn.CheckInStatus = 1 OR CheckIn.CheckIntatus = 2 OR CheckIn.CheckSIntatus = 3)
RIGHT JOIN Beds ON GuestBeds.BedId = Beds.Id
INNER JOIN Rooms ON Beds.RoomId = Rooms.Id
LEFT JOIN Guests ON CheckIn.GuestId = Guests.Id
WHERE Beds.Active = 1 AND Rooms.Active = 1
ORDER BY RoomName, Beds
It works well which means it shows all the RoomName with CheckInStatus. If the Room is not presence in CheckIn table, ot will return the status as Null.
So I want to convert the code to LINQ. SO here is my LINQ code:
from b in Beds
join w in Rooms on b.RoomsId equals w.Id
where (a.CheckInStatus == 3 || a.CheckInStatus == 1 || a.CheckInStatus == 2)
join p in GuestBeds on b.Id equals p.BedId
join a in CheckIn on p.Id equals a.GuestBedId
join t in Guests on a.GuestId equals t.Id
where b.Active == true && w.Active == true
orderby w.RoomName
select new
{
RoomName = w.RoomName,
BedName = b.BedName,
Status = a.CheckInStatus
}
It didnt worked like the first code. It only show the data which contain CheckInStatus. I want it to show all the RoomName inside Room database
Normally I would post some rules for converting SQL to LINQ but this is complicated enough I think I'd need to make new rules. I commented out the references to Guests because as a LEFT JOIN it has no bearing on the answer.
Pull out the WHERE on individual tables and make them sub-queries:
var ActiveBeds = Beds.Where(b => b.Active == 1);
var ActiveRooms = Rooms.Where(r => r.Active == 1);
In LINQ, a RIGHT JOIN must be done by flipping the join to be a left join, so we will create the two sides as sub-queries.
Left side of RIGHT JOIN:
Translate the JOIN conditions that aren't part of an equi-join into a LINQ where clause on the appropriate tables (alternately this could be a subquery as above). The LEFT JOIN becomes a LINQ join/from ... DefaultIfEmpty() phrase, but as noted above isn't needed.
var CheckInsGuestBedsGuests = from c in CheckIn
where (c.CheckInStatus == 1 || c.CheckInStatus == 2 || c.CheckInStatus == 3)
join gb in GuestBeds on c.GuestBedId equals gb.Id
//join g in Guests on c.GuestId equals g.Id into gj
//from g in gj.DefaultIfEmpty()
select new { c, gb /*, g */ };
Right side of RIGHT JOIN:
The other side of the RIGHT JOIN includes an INNER JOIN so put them together in a sub-query:
var ActiveBedsRooms = from b in ActiveBeds
join r in ActiveRooms on b.RoomId equals r.Id
select new { b, r };
Finally, flip the sub-queries to create a left join using the same idiom as above:
var ans = from br in ActiveBedsRooms
join cgbg in CheckInsGuestBedsGuests on br.b.Id equals cgbg.gb.BedId into cgbgj
from cgbg in cgbgj.DefaultIfEmpty()
select new {
RoomNo = br.r.RoomName,
Beds = br.b.BedName,
br.r.RoomType,
Status = cgbg.c.CheckInStatus
};
NOTE: If you were not using LINQ to SQL, the Status expression would fail when cgbg is null and you would need
Status = cgbg?.c.CheckInStatus
but unfortunately LINQ to SQL/EF doesn't handle the null conditional operators yet.
BTW, nice query - brings back memories of when I used to write hotel front desk software :)

LINQ Left Join with multiple ON OR conditions

I'm sorry for telling that I've a little bit weak on LINQ, I always do write SQL query before I start working on the complicated LINQ.
I want to ask that how to convert this SQL Query into LINQ with LEFT JOIN with multiple ON conditons with the OR operator.,
m.MerchandiseId will be use for twice in ON condition
SELECT
*
FROM
Inbox AS i
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS m ON
u.MerchandiseId = m.MerchandiseId
OR
i.ToMerchantId = m.MerchandiseId
WHERE
i.ToCompanyId = 10
OR
i.FromCompanyId = 10
var message = (from i in db.Inbox
join u in db.User on i.FromUserId equals u.UserId
join m in db.Merchandise on u.MerchandiseId equals m.MerchandiseId //here I want to ON i.MerchantId = m.MerchandiseId, but it doesn't allow
where i.ToCompanyId == user.CompanyId || i.FromCompanyId == user.CompanyId
orderby i.CreatedAt descending
group m.MerchandiseId by new { m.MerchandiseId, m.MerchandiseName } into grp
select new
{
MerchandiseId = grp.Key.MerchandiseId,
MerchandiseName = grp.Key.MerchandiseName,
InboxMessage = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.InboxMessage).FirstOrDefault(),
CreatedAt = (from e in db.Inbox
join us in db.User on e.FromUserId equals us.UserId
join mer in db.Merchandise on us.MerchandiseId equals mer.MerchandiseId
where mer.MerchandiseId == grp.Key.MerchandiseId
orderby e.CreatedAt descending
select e.CreatedAt).FirstOrDefault(),
}).ToList();
The bottom LINQ Query I've write for it. However, I just can work on the left join with multiple ON clause in LINQ. Appreciate if someone would help me on this. Thanks!
I don't believe Linq supports the use of the OR operator with multiple columns, but that said, I wouldn't use OR even in SQL as it makes the join's intention unclear and it also obscures where the data originated from - it also isn't immediately clear what happens if there are multiple matches for each column. Instead I would JOIN twice on the different columns and let the projection-clause handle it:
SELECT
*
FROM
Inbox
INNER JOIN [User] AS u ON i.FromUserId = u.UserId
LEFT OUTER JOIN Merchandise AS userMerchant ON u.MerchandiseId = userMerchant.MerchandiseId
LEFT OUTER JOIN Merchandise AS inboxMerchant ON Inbox.ToMerchantId = inboxMerchant .MerchandizeId
WHERE
Inbox.ToCompanyId = 10
OR
Inbox.FromCompanyId = 10
This can then be translated into Linq using the LEFT OUTER JOIN approach ( How to implement left join in JOIN Extension method )
Note that if you're using Entity Framework then you don't need to worry about doing any of this at all! Just use Include:
var query = db.Inbox
.Include( i => i.User )
.Include( i => i.User.Merchandise )
.Include i => i.Merchandise )
.Where( i => i.ToCompanyId = 10 || i.FromCompanyId == 10 );

LINQ to Entities - Multiple Joins on Same Table

I currently have some stored procedures in T-SQL that I would like to translate to LINQ-To-Entities for greater maintainability. However, no matter how I seem to construct the LINQ query, when I inspect the generated code, it's an abhorrent terribly-performing monstrosity. I've investigated into various combinations of "let" clauses, joins, shifting around the "where" clause to both inside and out of the anonymous type selection, or even using the extension ".Where<>()" method piecemeal in the other indiciations themselves, and nothing seems to generate code anywhere as close to what I would expect or need.
The difficulties seem threefold:
The joins that I need to do are on combinations of booleans, whereas LINQ-To-Entities seems to only have join functionality for equijoins. How can I translate these joins?
I need to join on the same table multiple different times with different join/where clauses, so that I can select a different value for each record. How do I accomplish this in LINQ-To-Entities?
How do I prevent my joins on entity collections become nested messes?
The T-SQL query I'm attempting to translate is this (where the hardcoded numbers are specific hardcoded types):
SELECT Transport.*,
[Address].Street1,
Carrier1Insurance.InsuranceNumber,
Carrier2Insurance.InsuranceNumber,
Carrier3Insurance.InsuranceNumber
FROM Transport
INNER JOIN Appoint ON Transport.AppointKEY = Appoint.AppointKEY
INNER JOIN Patient ON Appoint.PatientKEY = Patient.PatientKEY
LEFT OUTER JOIN [Address] ON [Address].AddressFKEY = Patient.PatientKEY AND [Address].AddressTypeByTableKEY = 1
LEFT OUTER JOIN PatientInsurance Carrier1Insurance ON Carrier1Insurance.PatientKEY = Patient.PatientKEY AND Carrier1Insurance.CarrierKEY = 7
LEFT OUTER JOIN PatientInsurance Carrier2Insurance ON Carrier2Insurance.PatientKEY = Patient.PatientKEY AND Carrier2Insurance.CarrierKEY = 8
LEFT OUTER JOIN PatientInsurance Carrier3Insurance ON Carrier3Insurance.PatientKEY = Patient.PatientKEY AND (Carrier3Insurance.CarrierKEY <> 7 AND Carrier3Insurance.CarrierKEY = 8)
WHERE (Transport.TransportDate >= '07-01-2013' AND Transport.TransportDate <= '07-31-2013')
AND EXISTS (SELECT TOP 1 *
FROM Remit
WHERE Remit.CarrierKEY = 8
AND Remit.AppointKEY = Transport.AppointKEY
AND Remit.PaidAmt > 0)
And the latest in many, many attempts at LINQ is this:
var medicareTransportList = from transportItem in ClientEDM.Transports
join patientAddress in ClientEDM.Addresses on transportItem.Appoint.PatientKEY equals patientAddress.AddressFKEY
join carrier1Insurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals carrier1Insurance.PatientKEY
join carrier2Insurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals carrier2Insurance.PatientKEY
join otherInsurance in ClientEDM.PatientInsurances on transportItem.Appoint.PatientKEY equals otherInsurance.PatientKEY
where (transportItem.TransportDate > fromDate ** transportItem.TransportDate <= toDate) && transportItem.Appoint.Remits.Any(remit => remit.CarrierKEY == 0 && remit.PaidAmt > 0.00M) &&
(carrier1Insurance.CarrierKEY == 7) &&
(carrier2Insurance.CarrierKEY == 8 ) &&
(otherInsurance.CarrierKEY != 7 &&
otherInsurance.CarrierKEY != 8 ) &&
(patientAddress.AddressTypeByTableKEY == 1)
select new
{
transport = transportItem,
patient = patientAddress,
medicare = medicareInsurance,
medicaid = medicaidInsurance,
other = otherInsurance
};
The LINQ .Join() operator is equivalent to the INNER JOIN SQL operator.
For any other case, use the .GroupJoin() operator.
But do you really need to use join? In many case, using LINQ, SQL JOIN (inner or outer) can be expressed using navigation properties between entities.
Please explains your conceptual data model for a precise answer.

LINQ JOIN different tables based on conditions

How can I join two different tables based on a condition?
I have my query as under:
var myquery = from p in db.tbl1
join q in db.tbl2 on p.field1 equals q.field1
join r in db.tbl3 on q.field2 equals r.field2
Till here everything is fine, now I want to add 1 more join to a table but it should be based on a condition like:
if(q.field3 == 1)
join s in db.tbl4 on q.field4 equals s.field4
else if(q.field3 == 2)
join s in db.tbl5 on ....
So basically I want to join to different tables based on the value of q.field3.
You're not going to be able to conditionally join based on the value of a single row. The idea of joining is that you're joining based off of all of the rows. Conditionally determining what/how to join based on some value outside of the query would make sense.
What you can do is do both joins unconditionally, but choose which result to use conditionally for each row. Obviously this will only work if the tables are of the same type, or if you first project s1 and s2 into a common type (using let)
var myquery = from p in db.tbl1
join q in db.tbl2 on p.field1 equals q.field1
join r in db.tbl3 on q.field2 equals r.field2
join s1 in db.tbl4 on q.field4 equals s1.field4
join s2 in db.tbl5 on q.field5 equals s2.field5
let s = q.field3 == 1 ? s1 :
q.field3 == 2 ? s2 : null
This should be able to be translated by the query provider into a CASE statement.

Categories