dynamic linq multiple vs single .where query - c#

Why does the single where query give a different result than multiple where queries ?
query.Where("666 = ID");
query.Where("ActiveFrom < #0 && ActiveTo > #1 && ValidFrom < DateTime.Now && ValidTo > DateTime.Now", toDate, fromDate);
query.ToString(); results in :
SELECT *
FROM [Country] AS [Extent1]
WHERE 666 = [Extent1].[ID]
and the same query with multiple where calls
query = query.Where("ActiveFrom < #0", toDate);
query = query.Where("ActiveTo > #0", fromDate);
query = query.Where("ValidFrom < DateTime.Now");
query = query.Where("ValidTo > DateTime.Now");
results in :
SELECT *
FROM [Country] AS [Extent1]
WHERE (666 = [Extent1].[ID]) AND
([Extent1].[ActiveFrom] < convert(datetime2, '2016-10-23 11:40:35.9538054', 121)) AND
([Extent1].[ActiveTo] > convert(datetime2, '2016-06-23 11:40:35.9518052', 121)) AND
([Extent1].[ValidFrom] < (SysDateTime())) AND
([Extent1].[ValidTo] > (SysDateTime()))

In order for the different Wheres to be relevant you need to assign them back to query:
//instead of:
query.Where("666 = ID");
query.Where("ActiveFrom < #0 && ActiveTo > #1 && ValidFrom < DateTime.Now && ValidTo > DateTime.Now", toDate, fromDate);
//do:
query = query.Where("666 = ID");
query = query.Where("ActiveFrom < #0 && ActiveTo > #1 && ValidFrom < DateTime.Now && ValidTo > DateTime.Now", toDate, fromDate);
Also the Where calls can be chained. Most linq extension methods return IEnumerable<TSource> and therefore can be chained.
Applying the chaining on your second query it will look like this:
query = query.Where("ActiveFrom < #0", toDate)
.Where("ActiveTo > #0", fromDate)
.Where("ValidFrom < DateTime.Now")
.Where("ValidTo > DateTime.Now");

Because the calls dont modify the query, they return a new instance representing the modified query instead. Thus the second example results in the big query whereas the first results in a simple where condition only.

Related

Combining multiple ef6 linq queries

I'm having an issue with combining multiple ef6 linq queries
Here the code works when the two linq queries are separated
List<int> skipRoomIds = hbContext.Reservations.Include(x => x.Room)
.Where(x => (x.FromDate < fromDate && fromDate < x.ToDate) || (x.FromDate < toDate && toDate < x.ToDate) ||
(fromDate < x.FromDate && x.FromDate < toDate) || (fromDate < x.ToDate && x.ToDate < toDate))
.Select(x => x.Room.Id).ToList(); //First query
roomRows = hbContext.Rooms.Where(x => !skipRoomIds.Contains(x.Id) && x.MaxNumOfPeople >= numOfPeople)
.Select(x=> new RoomRow() { From = fromDate, To = toDate, Room = x}).ToList(); //Second query
But when I try and combine the two I get an error:
System.NotSupportedException: 'LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[HotelBooker.Models.Reservation] Include[Reservation,Room](System.Linq.IQueryable`1[HotelBooker.Models.Reservation], System.Linq.Expressions.Expression`1[System.Func`2[HotelBooker.Models.Reservation,HotelBooker.Models.Room]])' method, and this method cannot be translated into a store expression.'
In the first linq query I get a list of integers to then use to check something in the where part of the second linq query, but then when I put the first linq query inside the second one it doesn't work.
Why would I want that ? well so I don't send more requests to the sql server then necessary.
roomRows = hbContext.Rooms.Where(z => !hbContext.Reservations.Include(x => x.Room)
.Where(x => (x.FromDate < fromDate && fromDate < x.ToDate) || (x.FromDate < toDate && toDate < x.ToDate) ||
(fromDate < x.FromDate && x.FromDate < toDate) || (fromDate < x.ToDate && x.ToDate < toDate))
.Select(x => x.Room.Id).AsEnumerable().Contains(z.Id)
&& z.MaxNumOfPeople >= numOfPeople)
.Select(z => new RoomRow() { From = fromDate, To = toDate, Room = z }).ToList();
Can anybody explain why combining multiple linq queries doesn't work with ef6 or if I'm doing it wrong ? and how would you do select statements in where or select part of an sql statement in linq ef6 ?
Sql statement example:
select * from table where id in (select id in table2);
I have tried searching for the answer but couldn't find anything, perhaps I had the wrong keywords when searching the problem.

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

SQL query to LINQ left outer join

I need help with converting a SQL query to LINQ. I tried with Linqer but that didn't give the expected results. This is my SQL query:
SELECT
dr.startDate,
dr.endDate,
SUM(CASE WHEN me.Size <= 10 THEN 1 ELSE 0 END) AS FirstGroup,
SUM(CASE WHEN me.Size > 10 AND me.Size <= 20 THEN 1 ELSE 0 END) AS SecondGroup,
SUM(CASE WHEN me.Size > 20 AND me.Size <= 30 THEN 1 ELSE 0 END) AS ThirdGroup,
SUM(CASE WHEN me.Size > 30 THEN 1 ELSE 0 END) AS FourthGroup,
MAX(ISNULL(me.Size,0)) AS MaxSize,
SUM(ISNULL(me.Size,0)) AS SpaceTotal
FROM
time_intervals dr
LEFT OUTER JOIN Rooms me
ON ( me.DateTime BETWEEN dr.startDate AND dr.endDate)
GROUP BY
dr.startDate,
dr.endDate
ORDER BY dr.startDate
The LINQ i tried is:
var stats = from t in time_intervals
from q in query
where q.DateTime >= t.startDate && q.DateTime <= t.endDate
select new {
Date = t.startDate,
First = (q.Size <= 10),
Second = (q.Size > 10 && q.Size <= 20),
Third = (q.Size > 20 && q.Size <= 30),
Fourth = (q.Size > 30)
};
But that didn't give the same result as the SQL query.
You are not using group keyword in your LINQ while you are grouping records by by start date and end date.
Try this code:-
var stats = (from t in time_intervals
from q in query.Where(m=> m.DateTime >= t.startDate && m.DateTime <= t.endDate).DefaultIfEmpty()
group q by new { t.startDate, t.endDate, q.Size } into g
select new
{
Date = g.Key.startDate,
First = g.Count(m=>m.Size <= 10)
}).OrderBy(m => m.startDate);

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";

How to convert nested sql statement to linq to entities?

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

Categories