.NET: LINQ's Last() - c#

I'm new to LINQ and LINQ to SQL and don't understand what's wrong with this code. The Excetpion.Message I get is
"Query operator 'Last' is not supported."
What I'm trying to do is get the earliest LastActivityUtcout of the latest 100. The code follows.
var postTimes = from post in db.Post
where post.LastActivityUtc != null
orderby post.LastActivityUtc descending
select post.LastActivityUtc;
DateTime startDate = DateTime.MinValue;
if (postTimes.Count() >= 2)
{
startDate = postTimes.Take(100).Last().Value;
}

Brandon has posted a solution, but it requires copying the whole list in memory.
If you just want to "transition" from database queries to in-process, you can use AsEnumerable:
startDate = postTimes.Take(100).AsEnumerable().Last().Value;
Having said that, you possibly do want to call ToList(), but earlier - to avoid having to execute the query once for the count, and once for the last value:
var postTimes = (from post in db.Post
where post.LastActivityUtc != null
orderby post.LastActivityUtc descending
select post.LastActivityUtc).Take(100).ToList();
DateTime startDate = DateTime.MinValue;
if (postTimes.Count >= 2)
{
startDate = postTimes.Last().Value;
}
That will execute the database query once, but only fetch the first 100 records into memory. Of course, it falls down somewhat if you were going to use postTimes elsewhere...

Call .ToList() on postTimes and then try using .Last()
startDate = postTimes.Take(100).ToList().Last().Value;

Related

LINQ to entites does not recognize Convert.ToDatetime method

EDIT All the other answers that link to a previous question's wont work for me because they are either using two tables or they know what startdate they are looking for.
I have the following LINQ query where i am trying to get the data from a table for the last 14 days. LINQ does not recognize Convert.ToDatetime method. The Query_Date column is a type string and i can't change it. How do i get the data i need?
var logs = (from bwl in db.UserActivities
where Convert.ToDateTime(bwl.Query_Date) >= DateTime.Now.AddDays(-14)
select new
{
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();
So i couldn't get what i wanted because i would have to make too many changes so the workaround i am doing is: I am using this code
var logs = db.UserActivities.ToList().Take(100);
This will get me the last 100 entries. I will give options for more or less entries then they can filter it on date in the search bar on the datatable.
It's not great but time is against me and this will suffice.
Do you have data being entered at least every day? If so, what about something like this:
var oldestDate = DateTime.Now.AddDays(-14);
var dateString = oldestDate.ToString(*/ your date format */);
var oldestID = db.UserActivities.First(b => b.Query_Date == dateString).Id;
var logs = (from bwl in db.UserActivities
where bwl.Id > oldestID
select new {
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();
Basically you find a record on that date and use its ID as a proxy for the date. This only works in certain circumstances (i.e. if the IDs are in date order).
This also isn't guaranteed to be the oldest entry on that date, but that could be achieved either by using ID order:
var oldestID = db.UserActivities.Where(b => b.Query_Date == dateString)
.OrderBy(b => b.Id)
.First().Id;
Or more lazily by using -15 instead of -14 when you add days, if you don't mind grabbing an unknown percentage of that 15th day.
Convert.ToDateTime works if your Query_Date has proper format. If not, check your string expression is convertable format.
I tested below code and it works fine when I assume Query_Date is a form of DateTime.toString().
var logs = (from bwl in db.UserActivities
where DateTime.Now - Convert.ToDateTime(bwl.Query_Date) <= TimeSpan.FromDays(14)
select new
{
Id = bwl.Id,
UserEmail = bwl.UserEmail
}).ToList();
I also tested with your where expression Convert.ToDateTime(bwl.Query_Date) >= DateTime.Now.AddDays(-14) and confirmed that it gives same result.

linq exception : This function can only be invoked from LINQ to Entities

I'm trying to get data which is kept on cache. But it throws an exception on "select new FilterSsrsLog" line. Exception: This function can only be invoked from LINQ to Entities
List<ExecutionLog3> reportServerDB = UpdateCache();
var reportLog = (from r in reportServerDB
orderby r.TimeStart descending
where ((model.reportName == null ? true : r.ItemPath.Contains(model.reportName)) &&
(model.reportFolder == null ? true : r.ItemPath.Contains(model.reportFolder)) &&
(r.TimeStart >= startDateTime) &&
(r.TimeStart <= endDateTime)
)
select new FilterSsrsLog
{
UserName = r.UserName,
ReportName = r.ItemPath,
ReportFolder = r.ItemPath,
Format = r.Format,
Parameters = r.Parameters,
TimeStart = r.TimeStart,
TimeEnd = r.TimeEnd,
TotalTime = EntityFunctions.DiffMilliseconds(r.TimeStart, r.TimeEnd)
});
If i remove "select new FilterSsrsLog" code block and write "select r" it works. But i need only that coloumns so what can i do to solve this problem?
The reason you are getting this error is that the query is executed in memory, not in RDBMS. The DiffMilliseconds function is a marker that Entity Framework provider converts to RDBMS-specific SQL to send to your RDBMS. The function does not compute its result when applied to an IQueryable<T> in memory, throwing an exception instead.
If you want to run this query in memory, replace
TotalTime = EntityFunctions.DiffMilliseconds(r.TimeStart, r.TimeEnd)
with
TotalTime = (r.TimeEnd - r.TimeStart).TotalMilliseconds
Subtraction of two dates produces a TimeSpan value from which you can take its TotalMilliseconds property.

Linq if DateTime field is older than X hours

I have tried the following (obviously without the //), but I can't get any to work, can anybody help please?
public void CleanBasket()
{
//double validHours = 3;
// var expired = (from a in db.Baskets where (DateTime.Now - a.DateCreated).TotalHours > validHours select a);
//var expired = (from a in db.Baskets where (DateTime.Now.Subtract(a.DateCreated).Hours > 3) select a);
//var expired = (from a in db.Baskets where(a => a.DateCreated > DateTime.Now.AddHours(-1));
//foreach (Basket basket in expired) db.DeleteObject(expired);
db.SaveChanges();
}
In this case surely you can simply do your date time calculation before you invoke LINQ:
double validHours = 3;
var latest = DateTime.UtcNow.AddHours(-validHours);
var expired = (from a in db.Baskets where a.DateCreated < latest select a);
For any more complex DateTime operations that you need to do in the database and cannot do this way you can use SqlFunctions.
BTW you should store your times in Utc not local time. Calculations using DateTime.Now will be wrong during daylight savings time changes.
My guess is that linq-to-entities doesn't know how formulate the query with the DateTime.Now operation. To do this, I would get the values in a list and then with just linq, filter them out.
public void CleanBasket()
{
var cutoff = DateTime.Now.Subtract(new TimeSpan(3, 0, 0));
var baskets = db.Baskets.Where(a=>a.DateCreated<cutoff);
db.DeleteObjects(baskets); // You can combine this with the last line
db.SaveChanges();
}
It is very likely that a ORM wont be able to translate TimeSpan operations, check this question it could be helpful: Comparing dates in query using LINQ
basically you can consider that if the method you are using does not have a literal translation to SQL it is very likely that it will not be supported.

Show data between a date range

Greetings
I have the personal data of an individual including birth date
How do I get the information of people born between the date 1 and date 2?
date of birth is in a SQL Server database Compact
I get a record this way
using (ISession session = NHibernateConfiguration.OpenSession())
{
var production = session
.CreateCriteria(typeof(Person))
.Add(Restrictions.Eq("Date", date))
.List<Person>();
return production;
}
instead of .Add(Restrictions.Eq("Date", date)) use .Add(Restrictions.Between("Date", fromDate, toDate))
If you have these Object's Stored on a List than you could say ,
for(int i=0;i<list.count;i++)
{
if(list[i].getBirthdate.Day == 1 || list[i].getBirthdate.Day == 2 )
//DoSomething
}
But man ,you should be more Specific ,if these Information's are Stored in DataBase ,if Birth Date is Stored As Formated DateTime or whatever ,please be more specific and show us some code.
By the tags in your question, it looks like you're using Nhibernate. If you use Linq-to-Nhibernate, then you could use a linq statement like this:
var query = myISession.Linq<Person>();
var result = from entity in query
where entity.Dob >= dob1 && entity.Dob <= dob2
select entity;
return result.Count() > 0 ? result.ToList() : null;
I like extensions methods much more
var persons = GetPersonList();
var range = persons.Where(p => p.Dob >= startDate && p.Dob <= endDate);
Note that I know this is basically the same as using LINQ syntax, I just don't like linq syntax :).

How do I perform Date Comparison in EF query?

Please help.
I am trying to figure out how to use DATE or DATETIME for comparison in a linq query.
Example:
If I wanted all Employee names for those who started before today, I would do something like this in SQL:
SELECT EmployeeNameColumn
FROM EmployeeTable
WHERE StartDateColumn.Date <= GETDATE() //Today
But what about linq?
DateTime startDT = //Today
var EmployeeName =
from e in db.employee
where e.StartDateColumn <= startDT
The above WHERE doesn't work:
Exception Details: System.NotSupportedException: The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
Use the class DbFunctions for trimming the time portion.
using System.Data.Entity;
var bla = (from log in context.Contacts
where DbFunctions.TruncateTime(log.ModifiedDate)
== DbFunctions.TruncateTime(today.Date)
select log).FirstOrDefault();
Source: http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/84d4e18b-7545-419b-9826-53ff1a0e2a62/
That should work. Are you sure that there isn't another part of the query that triggered the exception? I have several instances of queries of the form
var query = from e in db.MyTable
where e.AsOfDate <= DateTime.Now.Date
select e;
in my code.
It may be due to the date in the database being nullable. Try this:
var EmployeeName =
from e in db.employee
where e.StartDateColumn.Value <= startDT
You can check the condition like this
var nextDay = DateTime.Today.AddDays(1);
var query = from e in db.MyTable
where e.AsOfDate >= DateTime.Today && e.AsOfDate < nextDay
select e;
here you'll get the records on AsOfDate date as we checking between today(00:00:00) and tommorow(00:00:00) we'll get today's date record only what ever may be the time...
You can not use .Date
If you would like to check for today you can create a datetime with no time
DateTime myDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day);
var e = (from mds in myEntities.Table
where mds.CreateDateTime >= myDate
select mds).FirstOrDefault();
try this:
DateTime dd = DateTime.Parse("08/13/2010 00:00:00");
var data = from n in ContributionEligibilities
where n.ModifiedDateTime.Date >= DateTime.Parse("08/13/2010").Date
select n;
data.Dump("Result") ;
I'm curious to the error message saying 'Date', when you're passing a 'DateTime'. Could it be that 'StartDateColumn' is actually a 'Date', rather than a 'DateTime' in the database? That might mess up the comparison...
use a local variable to store the Date value and then use that variable in the query:
DateTime today = DateTime.Now.Date;
from scheme in context.schemes
where scheme.EndDate > today
select scheme
I am using a LinqDataSource and I had problems getting my query with a Date Comparison in it to execute without errors. The answer is to use the WhereAddParameters function and add the test value as a strongly typed parameter.
See the example below where I am matching a groupid and checking to see if the StopDate in my record is greater that or equal to a Date/Time stamp of now.
I am using this code fragment currently and it works like a charm.
LinqCampaigns.WhereParameters.Add("StopDate", System.Data.DbType.Date, DateTime.Now.ToString())
LinqCampaigns.Where = "GroupId = " & myGrp & " && " & "StopDate >= #StopDate"
Works like a charm....
.Date did not work, but .Day did for me.
var query = from o in Payments
where o.Order.OrderDate.Day != o.PaymentDate.Day
orderby o.Order.OrderDate
select new
{
o.Order.OrderID,
o.Order.OrderDate,
o.PaymentDate,
o.Order.FirstName,
o.Order.LastName,
o.Order.CustomerID
};
query.Dump();
ensure that you check null value like this :
'(from mm in _db.Calls
where mm.Professionnal.ID.Equals(proid)
&& mm.ComposedDate.HasValue &&
(mm.ComposedDate.Value >= datemin) && (mm.ComposedDate.Value <= date)
select mm).ToArray();'

Categories

Resources