Return Timespan ticks difference in LINQ queries - c#

I'm querying a list of objects, and I want to return a TimeSpan's ticks list of the difference between the time registered in the object, and now.
I wanted all in one expression, so:
var list = (from r in res where r.Site == "CNIS"
select Math.Abs((r.Timestamp.Value - DateTime.Now).Ticks)).ToList();
But I get the following error:
Exception Details: DbArithmeticExpression arguments must have a numeric common type
I already managed to do a workaround. For example, my code looks like this now:
var list = new List<long>();
foreach(var item in (from r in res where r.Site == "CNIS" select r))
list.Add(Math.Abs((item.Timestamp.Value - DateTime.Now).Ticks));
But what I really wanted to know is if it is possible to get the Timespan diff from a DateTime value to now, in a single LINQ query

It seems the error is relevant to the translation of your select statement into SQL.If fecthing the results form DB is not a problem you can do it using AsEnumerable and then project the items:
var now = DateTime.Now;
var list = res.Where(r => r.Site == "CNIS")
.AsEnumerable()
.Select(x => Math.Abs((x.Timestamp.Value - now).Ticks))
.ToList();
And since the value of DateTime.Now changes you should probably store the it into a variable and use it in the calculation.

Related

LINQ how to return group by as List?

I have a datatable that is populated with 2 columns, DateTime and Data. I have been able to group the list using:
var dates = table.AsEnumerable().GroupBy(x => Convert.ToDateTime(x["DateTime"]).ToShortDateString());
The conversion is to drop the "time" portion of the datetime as I only want 1 date per day so I can iterate over it.
I can see during debugging that the LINQ works out as I intended, but I have almost no experience in LINQ and I do not know how to return these results in a way that is iterable.
Below that LINQ statement I have:
foreach (string date in dates) {
string dummy2 = "";
}
with an error on foreach that says
Cannot convert type 'System.Linq.IGrouping<string, System.Data.DataRow>' to 'string'
The goal here is to return a list of just the unique dates which I can iterate over to perform additional processing/LINQ queries on the datatable
If you just want the dates, then you don't need to use GroupBy, you can use Distinct. Also, you can get them as a DateTime object by just grabbing the Date property, which has a zeroed-out time component:
IEnumerable<DateTime> distinctDates = table.AsEnumerable()
.Select(x => Convert.ToDateTime(x["DateTime"]).Date)
.Distinct();
If you want the groups but are just trying to select the date strings from them, then you want to use the Key property of the groups, which is the property that was used to group the items:
IEnumerable<IGrouping<string, System.Data.DataRow>> dates = table.AsEnumerable()
.GroupBy(x => Convert.ToDateTime(x["DateTime"]).ToShortDateString());
List<string> distinctDates = dates.Select(date => date.Key).ToList();
As a side note, unless you know the data type being returned by something, you might avoid using var, since that was hiding the fact that dates wasn't a collection of strings.
If you want a list of unique dates, you can do something like this.
var dates = table.Select(x => Convert.ToDateTime(x["DateTime"]).ToShortDateString()).Distinct();
that's happening since as the error says you're trying to loop in a dictionary:
Cannot convert type 'System.Linq.IGrouping<string, System.Data.DataRow>' to 'string'
what you can do is add to your GroupBy statement a select portion:
var dates = table.AsEnumerable().GroupBy(x => Convert.ToDateTime(x["DateTime"]).ToShortDateString()).Select(x=> x.date);

How to get data from linq query using select

I'm testing a simple LINQ select query and want to get two DateTime values from the table, but I'm doing something wrong here and need to know what I'm doing/thinking wrong?
My query:
var test = from x in db.Projects where x.ID == 1 select x;
Then I try to get on of the values like this:
DateTime Date = test. ?????
Here I thought I should get a suggestion from the Intellisense after the dot to pick the value from the column StartDate the table, but this isn't working.
If you need multiple matches...
Are you sure that you have multiple Project objects that have the same ID of 1 which your query currently suggests? If that is the case, then your query should return all of the records that meet that constraint via the Where() method :
// Get your Projects that meet your criteria
var test = db.Projects.Where(p => p.ID == 1);
If you need to access properties from these elements, you could either loop through them explicitly :
// Iterate through each match that was found
foreach(var t in test)
{
// Access your properties here
DateTime dt = t.YourDateProperty;
}
Or you could accomplish this using a Select() statement to only pull the properties that you need :
// This will return a collection of Dates mapped from each element in your collection
var testDates = db.Projects.Where(p => p.ID == 1)
.Select(x => x.YourDateProperty);
If you only need a single match...
If you only need to match a single element within your collection, you might consider using the First(), Single() or their equivalent FirstOrDefault() and SingleOrDefault() methods, which will return a single entity that you can use as expected :
// This will return the first Project with an ID of 1
var test = db.Project.FirstOrDefault(p => p.ID == 1);
// If it was successful
if(test != null)
{
// Then you can safely access it here
DateTime dt = test.YourDateProperty;
}
The only difference between the methods mentioned (normal vs OrDefault()) is that the OrDefault() methods will return null if no matching elements are found, so they generally require a null check as seen above.
test is going to be an enumeration (IEnumerable<>, IQueryable<>, etc... many are applicable) of your Project type. So if, for example, you want the first record, you might do this:
DateTime Date = test.First().SomeDateProperty;
All of the data returned from your query is in test. It could be zero records, one record, many records, etc.
In test you will have a collection which matches the condition x.ID == 1. You should iterate through that collection and take your needed properties.
Edit
I suggest you to use the syntax:
var result = db.Projects.FirstOrDefault(x => x.ID ==1);
this is such as:
var date = test.FirstOrDefault();
DateTime? Date = date != null ? date.StartDate : null;

Get the lowest year from LINQ query results

I am trying to find the earliest year from a group of rows returned by a LINQ query. The ActivationDate is stored as a datetime value in the DB.
I know that I can make a separate query to get just the date, but I would rather use the results from the existing query, as it is used for several other things.
IEnumerable<MonitoringPanel> panels = from rows in db.MonitoringPanels
where rows.DealerEntity == dealerIDint
select rows;
However this keeps throwing an error:
var testDate = panels.Min().ActivationDate;
Error:
System.ArgumentException was unhandled by user code.
It will throw an error even if I try to select the lowest PanelNumner (stored as an int), but the following does work:
var testDate = panels.FirstOrDefault().ActivationDate;
Solution
DateTime testDate = (DateTime)panels.Min( thing => thing.ActivationDate);
int lowYear = testDate.Year;
Unless the Enumerable is of a perimative type you need to add a lambda expression to tell it what property of the class to use. Try
var testDate = panels.Min(x => x.ActivationDate);
I think you need to tell the Min() method what to look for the Minimum of. Which field is the Minimum.
var testDate = panels.Min(panel => panel.ActivationDate);

ASP.NET MVC3: Applying a SELECT / WHERE Statement from MVC View

I have list of items contained in viewbag ViewBag.RoomBookings
As an example:
I want all the Roombookings with ViewBag.RoomBookings.RoomNo = 6 AND ViewBag.RoomBookings.Time < DateTime.Now AND ViewBag.RoomBookings.Time < DateTime.Now + 3600
Looping through is a NO.
And it must be done on the view, as I also need access to all the other roombookings too to populate a timetable.
Alternatively, Im thinking of Hash lists? Where I could list it with RoomNo, and Time and access it that way. But I cant find any good documentation on this if its even possible.
Ive tried a few things (just to test a method that works (these wont follow the same critera as above)):
var RoomBookingsTemp = ViewBag.RoomBookings;
var newlist = (from RoomOcc in RoomBookingsTemp where RoomOcc.EndDateTime < DateTime.Now select RoomOcc.RoomNo);
var bookings = RoomBookingsTemp.Where(roombooking => DateCheckStart < roombooking.EndDateTime && DateCheckEnd > roombooking.StartDateTime && roombooking.RoomNo == RoomNo);
var newlist = RoomBookingsTemp.Select(m => m["RentalNo"]);
But none are valid.
You need to cast the RoomBookingsTemp variable. When you declare it directly from the ViewBag it's still a dynamic type [details about viewbag] and the error your seeing is that linq can't query/iterate over a dynamic type.
I'm not sure what type you're actually using but try something like this...
var RoomBookingsTemp = ViewBag.RoomBookings as List<RoomBooking>;
or
List<RoomBooking> RoomBookingsTemp = ViewBag.RoomBookings;
What's wrong with your second method? You are just missing the select.
// Some statements removed from where for clarity
var bookings = RoomBookingsTemp.Where(rb => rb.RoomNo == 6).Select(rb => rb);

LINQ to Entities does not recognize the method 'System.String ToString()' method when converting Nullable DateTime

I'm trying to get the Day of the week from a Nullable DateTime and then Joining on a list of days.
My solution was to convert it to a DateTime first, but Linq to Entities doesn't like it.
LIST is an IEnumerable<string>
suggestions?
var result = from X in model.X
where X.StartDate.HasValue
join item in LIST on
Convert.ToDateTime(X.StartDate).DayOfWeek.ToString() equals item
select X;
Converting to a methods chain is no help:
var result = model.X.Where(x => x.StartDate.HasValue).Join(LIST,x => Convert.ToDateTime(x.StartDate).DayOfWeek.ToString(), item => item, (x, item) => x);
var result = from X in model.X
where X.StartDate.HasValue &&
List.Contains(SqlFunctions.DatePart("weekday", X.StartDate))
select X;
weekday returns an int so you should have a list of integers not strings
this will work if you use .ToList() before the convertion take place.
Entity 4.0 Casting Value As DateTime
var result = model.X.Where(x => x.StartDate.HasValue).ToList().Join(LIST,x => Convert.ToDateTime(x.StartDate).DayOfWeek.ToString(), item => item, (x, item) => x);
.ToString() is not supported by Linq-To-Entities, as are a number of other extension methods.
The short (and probably inaccurate to some degree) reason is that the .ToString() in the context above is sent to Sql Server to run in a query. Sql Server has no idea what .ToString() is, and so it fails when Sql Server's query parser tries to execute it.
also, FYI
http://msdn.microsoft.com/en-us/library/bb738550.aspx
EDIT: Do not use this code. It has been left here to show you what will not work and so you can see Chris' reasons why and how to solve.
Untested:
var result = from X in model.X
where ((X.StartDate != null) && X.StartDate.HasValue)
join item in LIST on
Convert.ToDateTime(X.StartDate).DayOfWeek.ToString() equals item
select X;
If you have declared StartDate as a Nullable field, it follows you should check for null values.

Categories

Resources