Changing my stored procedure to Linq - c#

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

Related

how to write linq query with where clause to get records between 9 am to 5 pm

how to write a linq query with to get records between 9 am 5 pm only. the records beyond that should be discarded.
timestamp datatype
code
var items = Pirs.Where(a => !a.dataFrame.EndsWith("AAAAAAAAAAA=") && (fromDate == null || fromDate.Value.Date <= TimeZoneInfo.ConvertTimeFromUtc(Convert.ToDateTime(a.timestamp), TimeZoneInfo.FindSystemTimeZoneById("India Standard Time")).Date) && (toDate == null || toDate.Value.Date >= TimeZoneInfo.ConvertTimeFromUtc(Convert.ToDateTime(a.timestamp), TimeZoneInfo.FindSystemTimeZoneById("India Standard Time")).Date))
.GroupBy(a => a.dataFrame.Substring(a.dataFrame.Length - 12))
.Select(g => g.First()).OrderBy(a => a.timestamp);
Pirs.Where(a.timestamp.TimeOfDay > new TimeStamp(9, 0, 0) && //all times after 9am
a.timestamp.TimeOfDay < new TimeStamp(17, 0, 0) && //all times before 5pm
a.timestamp.Date > fromDate && //all dates after fromData
a.timestamp.Date < toDate) //all dates before toDate
Do the following in where condition
TimeSpan span = TimeSpan.Parse("09:00:00");
TimeSpan espan = TimeSpan.Parse("17:00:00");
Pirs.Where(a => a.timestamp >= startDate && a.timestamp <= toDate && a.timestamp.TimeOfDay >= span && a.timestamp.TimeOfDay <= espan);

Entity framework "Select date time from string"

I need to select the records from a table for date interval.
But the date to select from is kept as nvarchar in this pattern
20160511_155015 (yyyymmdd_hhmmss)
I cannot use ToList() to make it as DateTime.ParseExact(entry.StartDate, "yyyyMMdd_HHmmss", CultureInfo.InvariantCulture)
The table keeps several millions records.
So I need to make something like this:
var preQuery = context.Table
.AsNoTracking()
.Select(x => new
{
StartDate = ConvertFrom()),
Mode = x.Mode,
SessionStart = x.AStart,
SessionEnd = x.AEnd,
x.SensorNumber
})
.Where(x => x.StartDate != null
&& x.StartDate >= startDate
&& x.StartDate <= endDate)
.ToList();
Is it possible to convert the string representation to Datetime and then proceed with Where clause ?
Please try this DateTime.ParseExact(dateTime ,format,CultureInfo.InvariantCulture);
var preQuery = context.Table.AsNoTracking().Select(x => new
{
StartDate = ConvertFrom(),
Mode = x.Mode,
SessionStart = DateTime.ParseExact(x.AStart,"yyyyMMdd_HHmmss", CultureInfo.InvariantCulture),
SessionEnd = DateTime.ParseExact(x.AEnd,"yyyyMMdd_HHmmss", CultureInfo.InvariantCulture),
x.SensorNumber
})
.Where(x => x.StartDate != null && x.StartDate >= startDate && x.StartDate <= endDate)
.ToList();
You can try:
StartDate.StartsWith("20160511") or so..
or
Convert.ToInt32(StartDate.Substring(0,8)) > 20160511
by the way, i think you might want to run a script, as long as it takes, and create a new column which will generate a DateTime based on that column

LINQ DateTime Query that ignores milliseconds

x.CreateDate DateTime is stored in our database down to milliseconds. My dateTimePicker values startdate and enddate only allows for querying down to seconds.
How can change my query to ignore the milliseconds of x.CreateDate? I thought the code I wrote below would work but it is not.
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.AddMilliseconds(-x.CreateDate.Millisecond) == startdate)
.OrderByDescending(x => x.ID)
.Take(count);
var query = from l in _context.Logs
where l.ApplicationID == applicationId
&& SqlMethods.DateDiffSecond(l.CreateDate,startdate) == 0
orderby l.ID descending
select l).Take(count);
This avoids converting every date in you table into a string and the subsequent string comparison, by comparing the two dates as dates.
Getting CreateDate and startdate in the same format will help you compare apples to apples. This should accomplish that.
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.ToString(#"MM/DD/YYYY h:mm:ss") == startdate.ToString(#"MM/DD/YYYY h:mm:ss")
.OrderByDescending(x => x.ID)
.Take(count);
I have no idea why I could not get any results from the queries posted above as I tried several variations of their themes. However I did get it working correctly by adding milliseconds to the startdate and enddate variables and it s working.
if (stardDateIsValid && endDateIsValid)
startdate = startdate.AddMilliseconds(000);
enddate = enddate.AddMilliseconds(999);
query = _context.Logs.Where(x => x.ApplicationID == applicationId && x.CreateDate >= startdate && x.CreateDate <= enddate).OrderByDescending(x => x.ID).Take(count);
You can create extension method.
public const long TicksPerMillisecond = 10000;
public const long TicksPerSecond = TicksPerMillisecond * 1000;
public static bool IsEqualIgnoreMilliseconds(this DateTime date, DateTime compareDate)
{
long tickDiff = date.Ticks - compareDate.Ticks;
return tickDiff > 0 ? tickDiff < TicksPerSecond : tickDiff < -TicksPerSecond;
}
Then you can use this:
if (stardDateIsValid && endDateIsValid && startdate == enddate)
query = _context.Logs
.Where(x => x.ApplicationID == applicationId &&
x.CreateDate.IsEqualIgnoreMilliseconds(startdate)
.OrderByDescending(x => x.ID)
.Take(count);

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

linq-to-sql null or default

I have a query that looks like this:
var TheQuery = (from....
where x.TheDate >= StartDate && x.TheDate <= EndDate
select new MyModel()
{
Total = (int?)x.Count() ?? 0,
....
}).Single();
Basically, I'm querying a number of records based between 2 dates. If for the date there are 0 values, it returns 0 as the Total. However, if there are no values at all, it returns null and crashes. I could add .SingleOrDefault() but it would return null instead of MyModel populated with a 0. The property Total is defined as an int.
How can I solve this?
Thanks
Count has an overload with a predicate, and returns 0 when no item matches the predicate
var result = new MyModel {
Total = <yourDataSource>
.Count(x.TheDate >= StartDate && x.TheDate <= EndDate)
};
if(TheQuery !=null || TheQuery .Count()>0){
//do something you wanna do
}
or
var v = TheQuery.ToList();
now check
if (v.Count > 0)
You should opt for:
int count = (from x in ...
where x.TheDate >= StartDate && x.TheDate <= EndDate
select c).Count();
That's what you want.
var TheQuery = (from....
where x.TheDate >= StartDate && x.TheDate <= EndDate
select new MyModel()
{
Total = (int?)x.Count() ?? 0,
....
}).DefaultIfEmpty(0).Single()'

Categories