How to convert nested sql statement to linq to entities? - c#

I'm trying to create a basic room availability statement to use with linq to entity framework. I have two tables: 'Room' including columns RoomID/RoomSize and 'Booking' including BookingID/RoomID/StartDate/Enddate.
I have got a working sql statement:
SELECT RoomID, RoomSize from Room
where RoomID NOT IN (SELECT RoomID from booking
where ('08/01/2015' >= [start] AND '08/01/2015' <= [end]) OR ('08/20/2015' >= [start] AND '08/20/2015' <= [end]))
I have got this far with the linq to entity statement:
var rooms = (from r in db.Rooms
where !(((from b in db.Bookings
where (startDate >= b.StartDate && endDate <= b.EndDate) || (endDate >= b.StartDate && endDate <= b.EndDate)).Contains(r.RoomID))
select new AvailableRoom
{
ID = r.RoomID,
Size = r.RoomSize
});
I get an error at the last bracket before .Contains(r.RoomID) saying I should have a select statement but I just can't seem to get it working.
Any suggestions would be welcome.
If you reckon using lambdas would be better/easier please feel free to suggest and example. I'm just not too familiar with them myself.. yet.
Thank you.

You can use LINQ !...Any() for the SQL NOT IN(), like so :
var rooms = (from r in db.Rooms
where !db.Bookings
.Where(b => (startDate >= b.StartDate && endDate <= b.EndDate)
||
(endDate >= b.StartDate && endDate <= b.EndDate)
)
.Any(b => b.RoomID == r.RoomID)
select new AvailableRoom
{
ID = r.RoomID,
Size = r.RoomSize
});

Related

Linq searches for recent birthdays (within 15 days)

How to use Linq
A table
Field Birthday
Linq searches for recent birthdays (within 15 days)
from a in Employee where a.PositionStatus == true select new{ a.Name,a.Birthday}
Try below query
var fromdate = DateTime.Now;
var todate = DateTime.Now.AddDays(15);
var result =
(
from a in Employee
where a.PositionStuats==true && a.DateOfBirth.Value.Month >= fromdate.Month &&
a.DateOfBirth.Value.Month <= todate.Month &&
a.DateOfBirth.Value.Day >= fromdate.Day && a.DateOfBirth.Value.Day <= todate.Day
select new{ a.Name,a.Birthday}
).ToList();
Depending on your entity frame work version you can also replace a.DateOfBirth.Value.Month with a.DateOfBirth.Month.

Changing my stored procedure to Linq

I have a question regarding how to convert the following to linq. I've been trying to get my head around ASP.NET MVC, and one of the biggest hurdles for me is Linq.
CREATE PROCEDURE [dbo].[SelectAvailableCoops]
#startDate DATETIME, #endDate DATETIME
AS
BEGIN
SET NOCOUNT ON;
SELECT ID, coopName, coopCPN
FROM tbl_Coops
WHERE ID NOT IN (SELECT coopID
FROM tbl_bookings
WHERE (startDate <= #startDate AND endDate >= #startDate)
OR (startDate < #endDate AND endDate >= #endDate)
OR (#startDate <= startDate AND #endDate >= endDate)
)
END
GO
If it helps, at the moment I have the following in my action result.
BookingsListVM bookinglist = new BookingsListVM();
//bookinglist.Customers = db.Customers.ToList();
bookinglist.Customers = (from c in db.Customers select c).ToList();
bookinglist.CustomerBookings = (from cb in db.CustomerBookings select cb).ToList();
bookinglist.Coops = (from co in db.Coops select co).ToList();
Well here is one
db.Customers.Where(x=> db.CustomerBookings.Any(a=> a.coopID != x.Id &&
((a.StartDate <= startDate && a.EndDate >= enddate)
||
(a.StartDate < endDate && a.EndDate >= enddate)
||
(a.StartDate <= startDate && a.EndDate >= endDate)
)));
The other answer looks better but here is a slightly longer solution that is hopefully a bit easier to understand.
//Returns IDs
var bookingIds = tbl_bookings
.Where(b => b.ReleaseDate <= startDate && b.ReleaseDate >= endDate
|| (b.ReleaseDate < endDate && b.ReleaseDate >= endDate)
|| (b.ReleaseDate <= startDate && b.ReleaseDate >= endDate))
.Select(b => b.Id);
//Returns anonymous object list containing all records
//with an ID not found in previous result set
var bookings = tbl_bookings.Where(b => !bookingIds.Contains(b.Id))
.Select(b => new { ID = b.Id, CoopName = b.Id, coopCPN = b.Id })
.ToList();

LINQ JOIN with 3 tables where two of them have many-to-one relations

Hy. I'm working on a query, which should join 3 tables like
client - has ID - take his name
banking - has clientid - take some data from bankDate to bankDate
marketing - has clientid - take some data from marketDate to marketDate
code:
var totals = from client in _db.Clients
join bank in _db.Banking on client.Id equals bank.ClientId
where (client.Id == bank.ClientId &&
DateTime.Compare(bank.BankDate, (DateTime) fromDate) >= 0 &&
DateTime.Compare(bank.BankDate, (DateTime) toDate) <= 0)
join market in _db.Marketing on client.Id equals market.ClientId
where (client.Id == market.ClientId &&
DateTime.Compare(market.MarketDate, (DateTime) fromDate) >= 0 &&
DateTime.Compare(market.MarketDate, (DateTime) toDate) <= 0)
select new {client.Username, bank, market};
This algorithm doesn't provide successful join for the tables with many-to-one relations.
Who has ever faced this problem and knows how to solve it? I'll be very appreciated for any help
I am assuming that the where statement is not referencing the correct table.
Try this: (might be syntax error)
var totals = from client in _db.Clients
join bank in _db.Banking.Where(x => DateTime.Compare(x.BankDate, (DateTime) fromDate) >= 0 &&
DateTime.Compare(x.BankDate, (DateTime) toDate) <= 0) on client.Id equals bank.ClientId
join market in _db.Marketing.Where(x => DateTime.Compare(x.MarketDate, (DateTime) fromDate) >= 0 &&
DateTime.Compare(x.MarketDate, (DateTime) toDate) <= 0) on client.Id equals market.ClientId
select new {client.Username, bank, market};
By many-to-one I guess you are looking for left outer join, try this.
var totals = from client in _db.Clients
join bank in _db.Banking on client.Id equals bank.ClientId into banks
from bank in banks.DefaultIfEmpty()
where (client.Id == bank.ClientId &&
DateTime.Compare(bank.BankDate, (DateTime)fromDate) >= 0 &&
DateTime.Compare(bank.BankDate, (DateTime)toDate) <= 0)
join market in _db.Marketing on client.Id equals market.ClientId into markets
from market in markets.DefaultIfEmpty()
where (client.Id == market.ClientId &&
DateTime.Compare(market.MarketDate, (DateTime)fromDate) >= 0 &&
DateTime.Compare(market.MarketDate, (DateTime)toDate) <= 0)
select new { client.Username, bank, market };

How to add a Case statement to my LINQ Query

I have a JS table that i populate using a Linq Statement. Im fairly new to LINQ and i really need this LINQ statement so that i can finish off my project.
Here is my LINQ Statement. (That where statement is wrong because the database values are wrong, the linq will fix everything)
MSCDatabaseDataContext MSCDB = new MSCDatabaseDataContext();
var q = from row in MSCDB.Tbl_Campaigns
join cs in MSCDB.tbl_StatusOfCampaigns on row.CampaignStatus equals cs.ID
where ((row.CampaignStatus == 0) ||
(row.CampaignStatus == 1) ||
(row.CampaignStatus == 2) ||
(row.CampaignStatus == 3))
select new Campaign
{
CampaignID = row.CampaignId,
CampaignName = row.CampaignName,
Target = Convert.ToInt32(row.Target),
Discount = Convert.ToInt32(row.Discount),
CampaignSDate = Convert.ToDateTime(row.StartDate),
CampaignEDate = Convert.ToDateTime(row.EndDate),
CurrentStatus = replaceStatus((row.CampaignStatus.ToString())),
Uptake = Convert.ToInt32(row.Uptake),
};
I Basically want to remove that Where caluse and the inner join, And i can have a Case statement to display values based on dates.
CASE
WHEN EndDate >= GETDATE() and StartDate <= GETDATE() THEN 'Active'
WHEN StartDate >= GETDATE() THEN 'Pending'
ELSE 'Closed'
END as 'CurrentStatus',
The help would be greatly appreciated. (You can remove the where caluse and inner join as it will not be needed.)
by using the conditional operator you can solve this in one line
CurrentStatus = row.EndDate >= DateTime.Now && row.StartDate <= DateTime.Now ? "Active": row.StartDate >= DateTime.Now ? "Pending": "Closed";

SQL into LINQ to Entities

I have a big problem.
I'm for last 5 year SQL-boy, but now I need to convert my SQL query into LINQ to entity C# format.
Because I'm new in LINQ (complex statements) right now I need fast help.
Thank's in advance.
P.S. also I need some advices, some start point to start rapidly to learn LINQ to entities.
Here is my SQL (direct from my app(#endDate,#endDate and #glChartID remain as parameters also in my c# app)):
SELECT budget.accountid,
budget.perioddate,
budget.lastyear,
budget.thisyear,
budget.budget,
budget.operplan,
budget.forecast,
glchart.accounttype,
glchart.headertype
FROM budget INNER JOIN glchart ON budget.accountid = glchart.id
WHERE budget.accountid = #glChartID AND budget.perioddate BETWEEN #startDate and #endDate AND glchart.headertype NOT LIKE 'Header%'
UNION
SELECT glchart.id,
budget.perioddate,
SUM(ISNULL(budget.lastyear, 0)),
SUM(ISNULL(budget.thisyear, 0)),
SUM(ISNULL(budget.budget, 0)),
SUM(ISNULL(budget.operplan, 0)),
SUM(ISNULL(budget.forecast, 0)),
glchart.accounttype,
glchart.headertype
FROM budget INNER JOIN glchart ON budget.accountid = glchart.id
WHERE budget.accountid
IN
(SELECT g.id FROM glchart g
WHERE g.code >= glchart.code AND g.code <
CASE
WHEN glchart. headerlevel = 1 AND
(SELECT MAX(g3.code)
FROM glchart g3
WHERE g3.headerlevel = 1
) = glchart.code
THEN
(SELECT MAX(g2.code)
FROM glchart g2
WHERE g2.code >= g.code)
ELSE
(SELECT MIN(g2.code)
FROM glchart g2
WHERE g2.code > glchart.code AND
g2.headerlevel = glchart. headerlevel) END ) AND
glchart.id = #glChartID AND
budget.perioddate BETWEEN #startDate AND #endDate AND
glchart.headertype LIKE 'Header%'
GROUP BY glchart.id, budget.perioddate, glchart.accounttype, glchart.headertype
Until today, I managed (thanks to DOK)how to do it and this is how my LINQ is look like right now:
var query = ((ObjectQuery<Budget>)(
from budgets in this.ObjectContext.Budgets
join glcharts in this.ObjectContext.GLCharts on new { AccountID = budgets.AccountID } equals new { AccountID = glcharts.ID }
where
(!(from glC in this.ObjectContext.GLCharts
where Convert.ToInt16(glC.Code) >= Convert.ToInt16(glcharts.Code) && glC.Code != (Convert.ToInt64(glcharts.HeaderLevel) == 1 &&
(from g3 in this.ObjectContext.GLCharts
where Convert.ToInt64(g3.HeaderLevel) == 1
select new {g3.Code}).Max(p => p.Code) == glcharts.Code ?
(from g2 in this.ObjectContext.GLCharts
where Convert.ToInt16(g2.Code) >= Convert.ToInt16(glC.Code)
select new {g2.Code}).Max(p => p.Code) :
(from g2 in this.ObjectContext.GLCharts
where Convert.ToInt16(g2.Code) > Convert.ToInt16(glcharts.Code) && g2.HeaderLevel == glcharts.HeaderLevel
select new {g2.Code}).Min(p => p.Code))
select new {glC.ID}
).Contains(new { budgets.AccountID }) &&
glcharts.ID == 2376 && budgets.PeriodDate >= StartDate &&
budgets.PeriodDate <= EndDate &&
glcharts.HeaderType.StartsWith("Header"))
).Contains(new { budgets.AccountID }) && glcharts.ID == 2376 && budgets.PeriodDate >= StartDate && budgets.PeriodDate <= EndDate && glcharts.HeaderType.StartsWith("Header")
group new {glc = glcharts, b = budgets}
by new {
glcharts.ID,
budgets.PeriodDate,
glcharts.AccountType,
glcharts.HeaderType
} into g
select new {
AccountID = (System.Int32?)g.Key.ID,
PeriodDate = (System.DateTime?)g.Key.PeriodDate,
LastYear = g.Sum(p => ((System.Decimal?)p.t.LastYear ?? (System.Decimal?)0)),
ThisYear = g.Sum(p => ((System.Decimal?)p.t.ThisYear ?? (System.Decimal?)0)),
Budget = g.Sum(p => ((int?)p.t.Budget1 ?? (int?)0)),
OperPlan = g.Sum(p => ((System.Decimal?)p.t.OperPlan ?? (System.Decimal?)0)),
Forecast = g.Sum(p => ((System.Decimal?)p.t.Forecast ?? (System.Decimal?)0)),
AccountType = g.Key.AccountType,
HeaderType = g.Key.HeaderType
}));
return query;
But in THIS LINE: .Contains(new { budgets.AccountID }) I'm getting next error :
Error 8'System.Linq.IQueryable' does not contain a definition for 'Contains' and the best extension method overload 'System.Linq.ParallelEnumerable.Contains(System.Linq.ParallelQuery, TSource)' has some invalid arguments
Does anybody have an idea where I'm wrong?
Thanks to everyone.
You might find some help in this excellent reference site.
That will lead you to, for example, two examples for UNION.
If you really must start out at this level of difficulty, you might consider breaking your SQL down into pieces and getting them working bit by bit. Do the first SELECT without the JOIN or WHERE, then add those one at a time. Then do the second SELECT the same way. Then add the UNION.
By the time you get this one worked out, SQL-boy, you will definitely be LINQ-man!

Categories