date comparison in EF query - linq

I have a EF query in which i'm using lambda expressions, when i try to get the difference between two dates, it throws me exception
The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.
my query is
var unApprovedLeaves = db.Leaves.Where(l => l.Status.Id == 1 && ((System.DateTime.Now.Date - l.ToDate.Date).TotalDays)==0)
.Include("Employee")
.Include("Employee.Manager")
.ToList();
can anyone tell me how do i get this thing right?

You must use SqlFunctions helper from System.Data.Objects.SqlClient. Try this:
var today = DateTime.Now.Date;
var unApprovedLeaves = db.Leaves.Where(l => l.Status.Id == 1 &&
(SqlFunctions.DateDiff("day", today, l.ToDate))==0)
.Include("Employee")
.Include("Employee.Manager")
.ToList();

In Entity Framework it is recomended to use DbFunctions helper from System.Data.Entity
Try this:
var today = DateTime.Now.Date;
var unApprovedLeaves = db.Leaves.Where(l => l.Status.Id == 1 &&
(DbFUnction.DiffDays(today, l.ToDate))==0)
.Include("Employee")
.Include("Employee.Manager")
.ToList();

Related

LINQ to Entities does not recognize the method 'System.Collections.Generic.List`1[System.Int32]

I have the following error:
LINQ to Entities does not recognize the method
'System.Collections.Generic.List`1 [System.Int32] get_st_past_enrollment_success()'
method, and this method cannot be translated into a store expression.
This is caused by the following linq
IEnumerable<subject> _subjects = (from subject in context.subjects
where
subject.enrollments.Count() < subject.sj_max_enrollment
&& subject.sj_availability == true
&& !this.get_st_past_enrollment_success().Contains(subject.sj_subject_id)
select subject);
get_st_past_enrollment_success() returns a List:
public List<int> get_st_past_enrollment_success()
{
return this.enrollments.Where(e => e.em_enrolled == false && e.em_result >= 50).Select(e => e.em_subject_id).ToList();
}
What am i doing wrong here?
Your query itself contains the method call - and Entity Framework doesn't know what to do with that. Try extracting the list fetch to before the query:
var enrollments = get_st_past_enrollment_success();
var _subjects = from subject in context.subjects
where subject.enrollments.Count() < subject.sj_max_enrollment
&& subject.sj_availability
&& !enrollments.Contains(subject.sj_subject_id)
select subject;
Also note that get_st_past_enrollment_success violates .NET naming conventions - that won't affect whether the code works, but it'll look odd to other developers who are used to the normal conventions.

The specified type member 'Date' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties

Using this code in Entity Framework I receive the following error. I need to get all the rows for a specific date, DateTimeStart is of type DataType in this format 2013-01-30 12:00:00.000
Code:
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference)
.Where(x => x.DateTimeStart.Date == currentDateTime.Date);
Error:
base {System.SystemException} = {"The specified type member 'Date' is
not supported in LINQ to Entities. Only initializers, entity members,
and entity navigation properties are supported."}
Any ideas how to fix it?
DateTime.Date cannot be converted to SQL. Use EntityFunctions.TruncateTime method to get date part.
var eventsCustom = eventCustomRepository
.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference)
.Where(x => EntityFunctions.TruncateTime(x.DateTimeStart) == currentDate.Date);
UPDATE: As #shankbond mentioned in comments, in Entity Framework 6 EntityFunctions is obsolete, and you should use DbFunctions class, which is shipped with Entity Framework.
You should now use DbFunctions.TruncateTime
var anyCalls = _db.CallLogs.Where(r => DbFunctions.TruncateTime(r.DateTime) == callDateTime.Date).ToList();
EntityFunctions is obsolete. Consider using DbFunctions instead.
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference)
.Where(x => DbFunctions.TruncateTime(x.DateTimeStart) == currentDate.Date);
I would like to add a solution, that have helpt me to solve this problem in entity framework:
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference)
.Where(x => x.DateTimeStart.Year == currentDateTime.Year &&
x.DateTimeStart.Month== currentDateTime.Month &&
x.DateTimeStart.Day == currentDateTime.Day
);
I hope that it helps.
Always use EntityFunctions.TruncateTime() for both x.DateTimeStart and currentDate.
such as :
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference).Where(x => EntityFunctions.TruncateTime(x.DateTimeStart) == EntityFunctions.TruncateTime(currentDate));
Just use simple properties.
var tomorrow = currentDateTime.Date + 1;
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference)
.Where(x => x.DateTimeStart >= currentDateTime.Date
and x.DateTimeStart < tomorrow);
If future dates are not possible in your app, then >= x.DateTimeStart >= currentDateTime.Date is sufficient.
if you have more complex date comparisons, then check Canonical functions
and if you have EF6+ DB functions
More Generally - For people searching for issues Supported Linq methods in EF
can explain similar issues with linq statements that work on Memory base Lists but not in EF.
Simplified:
DateTime time = System.DateTime.Now;
ModelName m = context.TableName.Where(x=> DbFunctions.TruncateTime(x.Date) == time.Date)).FirstOrDefault();
Use the bellow code for using EF6:
(DbFunctions.TruncateTime(x.User.LeaveDate.Value)
I have the same issue with Entity Framework 6.1.3
But with different scenario. My model property is of type nullable DateTime
DateTime? CreatedDate { get; set; }
So I need to query on today's date to check all the record, so this what works for me. Which means I need to truncate both records to get the proper query on DbContext:
Where(w => DbFunctions.TruncateTime(w.CreatedDate) == DbFunctions.TruncateTime(DateTime.Now);
Another solution could be:
var eventsCustom = eventCustomRepository.FindAllEventsCustomByUniqueStudentReference(userDevice.UniqueStudentReference).AsEnumerable()
.Where(x => x.DateTimeStart.Date == currentDate.Date).AsQueryable();
I've faced this same issue and it seems that it is really caused by the presence of a call to the .Date property within the Where method. When removed, the error disappears. Consider that calling the .Date property on any side of the comparison operator causes this error. Calling the .Date property outside and before the Where method is enough to solve this error.

Error getting items from Entity Framework using Lambda query

I have a listbox that I am trying to populate with the result of a SQL Server query via a Entity Framework linq/lambda query. I am feeding the query with a value from a combobox. I keep getting lot of errors like the following: Unable to create a constant value of type 'System.Object'. Only primitive types ('such as Int32, String, and Guid') are supported in this context.
Any suggestions on how to fix this? I just want two fields to populate in a grid
var pAt = ent.Patterns.Where(p => p.Case_Id == (cbCase.SelectedItem as Case).Case_Id).Select(x => new Pattern{ PatternID = x.PatternID, Pattern1 = x.Pattern1 });
listBox1.DataSource = pAt;
listBox1.ValueMember = "PatternID";
listBox1.DisplayMember = "Pattern1";
Try this instead :
var pAt = ent.Patterns.AsEnumerable()
.Where(p => p.Case_Id == ((Case)cbCase.SelectedItem).Case_Id)
.Select(x => new Pattern{ PatternID = x.PatternID, Pattern1 = x.Pattern1 });
Hope this will fix your issue.
Separate the code parts from the SQL parts. Entity Framework can't necessarily construct an SQL query using code objects, but you can usually work around it. Eg:
var caseId = (cbCase.SelectedItem as Case).Case_Id;
var pAt = ent.Patterns.Where(p => p.Case_Id == caseId)
.ToArray()
.Select(x => new Pattern { PatternID = x.PatternID, Pattern1 = x.Pattern1 });

DateTime and LinqToEntities

I have DateTime field, which storing date + time. I need to use only date part, so I try:
query = query.Where(p => p.CreatedDateTime.Date == DateStart);
but I get the following error:
The specified type member 'Date' is not supported in LINQ to Entities.
Only initializers, entity members, and entity navigation properties
are supported.
why and how to fix it?
what about this:
query = query.Where(p => EntityFunctions.TruncateTime(p.CreatedDateTime) == DateStart);
You cannot use extension functions in LINQ queries that result in a database hit if Entity Framework has no way to convert this into valid SQL.
There may be a more compact solution but the following should work fine:
query = query.Where(p =>
p.CreatedDateTime.Year == DateStart.Year &&
p.CreatedDateTime.Month == DateStart.Month &&
p.CreatedDateTime.Day == DateStart.Day);

linq sort many 2 many question

My main entity is called [Contract]. Contract has a many 2 many relationship w/ [Service].
When I query for a list of Contracts I grab the 1st Service available like this:
IQueryable<Contract> q = ctx.Contracts.Skip(startRow - 1).Take(pgSize);
q.Select(c =>
new ContractSearchResult()
{
ContractID = c.ContractID,
FirstService = c.Contract2Service.FirstOrDefault().Service.Name,
ServiceCount = c.Contract2Service.Count,
}
).ToList();
(When I display this list I show the FirstService if there's only 1. If > 1 I show "My1stService (3)" to show I'm seeing the 1st of 3 services) This works fine.
My question is this:
Is there any way to sort by FirstService? Or is this impossible? I haven't found a way of expressing this in linq and allow for paging.
Any help would be appreciated.
You need to OrderBy before you page.
var result = ctx.Contracts
.Select(c =>
new ContractSearchResult()
{
ContractID = c.ContractID,
FirstService = c.Contract2Service.FirstOrDefault().Service.Name,
ServiceCount = c.Contract2Service.Count,
})
.OrderBy(x => x.FirstService)
.Skip(startRow - 1)
.Take(pgSize)
.ToList();
Also note that FirstOrDefault can return null and you should check for that. If you know that it will (or should) never be null then use First instead.
q.OrderBy(c => c.Contract2Service.FirstOrDefault().Service.Name)
.Select(c =>
new ContractSearchResult()
{
ContractID = c.ContractID,
FirstService = c.Contract2Service.FirstOrDefault().Service.Name,
ServiceCount = c.Contract2Service.Count,
}
)
.ToList();
Unless I'm missing something in your question (which is possible), it should be as simple as calling OrderBy() after your call to Select()

Resources