LINQ to Entities does not recognize the method 'System.DateTime ToDateTime(System.String)' method - sql

Hello This is my first post here
I'm facing some issue with EF , I have tried the following code in VS 2010 with EF 5 and 6.
I have table called MYTABLE and field ReveivedTime which varchar(255) but this has Datetime values like "4/29/2014 12:00:00 AM".
Note : I can not change the DataType and I can not write SP to Convert , I do have limitations, So I do have option to work with LAMBDA
I have tired the following code in LINQPad 4 itis working fine but the same is not working in VS2010 with EF 5/6.
getting error
LINQ to Entities does not recognize the method 'System.DateTime ToDateTime(System.String)' method, and this method cannot be translated into a store expression.
Convert.ToDateTime(si.ReceivedTime) is causing the problem
MYTable
.Where (
si =>
((Convert.ToDateTime(si.ReceivedTime) >= DateTime.Now.AddDays(-10)) &&
(Convert.ToDateTime (si.ReceivedTime) <= DateTime.Now)
)
)
.GroupBy (g => new
{
Day = Convert.ToDateTime(g.ReceivedTime).Day,
Month = Convert.ToDateTime(g.ReceivedTime).Month,
Year = Convert.ToDateTime(g.ReceivedTime).Year,
City = g.City,
})
.Select (
g =>
new
{
Count = g.Count(),
g.Key.Day,
g.Key.Month,
g.Key.Year,
g.Key.City,
Date = Convert.ToDateTime(g.Key.Year + "/" + g.Key.Month + "/" + g.Key.Day),
}
)
.OrderBy(x => x.Count)
Really appreciate your solution and advanced thanks too.

Instead of Convert.ToDateTime (si.ReceivedTime) <= DateTime.Now try SqlFunctions.DateDiff("s", si.ReceivedTime, DateTime.Now) > 0

Related

Convert SQL to LINQ/EF

I want to convert this SQL query to LINQ. But I'm new in EF. Please help
SQL Query
select * from VersionHistory where id in( select OptionsId from StylesHistory where ConId=540 and OptionsId = 28286 and ModifiedAtVersion>1)
TIA
I tried Something like this
var stylesHistory = _context.VersionHistory
.Where(x => x.ModifiedAtVersion > 1
&& x.Id==28286
&& x.Contract.Id==540)
.ToList()
Not Sure How I can add Sub Query
You can easily write that as:
var result = ctx.VersionHistory
.Where(vh => ctx.StylesHistory
.Any( sh => sh.OptionsId == vh.Id &&
sh.OptionsId == 28286 &&
sh.ConId = 540 &&
sh.ModifiedAtVersion > 1));
You can also create your subquery as another IEnumerable which you'll use in the main query.
This will improve readibility.
EF will only generate one query.

Rewriting SQL to LINQ [duplicate]

This question already has answers here:
How can you handle an IN sub-query with LINQ to SQL?
(9 answers)
Closed 6 years ago.
I'm completely new to LINQ, i want to rewrite some of mine SQL querys into LINQ (just to learn) and i'v already stuck at the beginning.
Here is SQL query :
declare #typMon varchar(200)
set #typMon = 'moneta'
select *
from [db1].[dbo].[Picking]
where number = 1000
and Group IN (Select grupa
from [db2].[dbo].[groups]
where typ = #typMon)
Subquery returns 3 output rows : http://i.stack.imgur.com/CDOwr.png
And here is what i'v write in LINQ
This part works ok :
var query = from x in db.grupyTowarowes
where x.typ == typMoneta
select new
{
x.grupa
};
Problem is here:
var test = from z in dbContext.PICKINGs
where z.Number == 1000
&& z.group IN output from 1st query
select new
{
z.id
};
var test = from z in dbContext.TBL_CSV_PICKINGs
join g in db.grupyTowarowes on Z.group equals g.grupa
where z.Number == 1000 &&
g.typ == typMoneta
select new { z.id };
Or in the Method syntax
dbContext.TBL_CSV_PICKINGs
.Where(z => z.Number == 1000)
.Join(db.grupyTowarowes.Where(g => g.typ == typMoneta)
z => z.group,
g => g.grupa,
(z,g) => z.id);

SQL to Linq group by count

I have a single column in a table to count specific rows. The sql query is as below:
SELECT
CASE
WHEN trail LIKE 'ClassA%' THEN 'ClassA'
WHEN trail LIKE 'ClassB%' THEN 'ClassB'
WHEN trail LIKE 'SemA%' THEN 'SemesterA'
WHEN trail LIKE 'SemB%' THEN 'SemesterB'
END AS Logs
, COUNT(*) AS Count
FROM Logs where s_date >= 'from date from UI' and e_date <= 'to date from ui'
GROUP BY
CASE
WHEN trail LIKE 'ClassA%' THEN 'ClassA'
WHEN trail LIKE 'ClassB%' THEN 'ClassB'
WHEN trail LIKE 'SemA%' THEN 'SemesterA'
WHEN trail LIKE 'SemB%' THEN 'SemesterB'
END
The above query result in sql fine as
ClassA 20
ClassB 5
SemesterA 2
SemesterB 50
Now, I need to change this sql to Linq with a date filter (from date, to date).
Please suggest change in query to simplyfy it.
Thanks
Tried:-
var data = _db.Logs.Where(p => p.trail.StartsWith("ClassA") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("ClassA")).Select(s =>
new
{
source = "Class - A total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("ClassB") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("ClassB")).Select(s =>
new
{
source = "Class - B total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("SemesterA") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("SemesterA")).Select(s =>
new
{
source = "Semester - A total",
percentage = s.Count()
}).Union(_db.Logs.Where(p => p.trail.StartsWith("SemesterB") && (p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)).GroupBy(p => p.trail.StartsWith("SemesterB")).Select(s =>
new
{
source = "Semester - B total",
percentage = s.Count()
})))).ToList();
Try storing all the interesting starting keys in an enumerable of some sort and then using the built in group by method overload which outputs a result mapped from the key,group pairs (c.f. https://msdn.microsoft.com/en-us/library/vstudio/bb549393(v=vs.100).aspx)
string[] startingKeys = new string[] {"ClassA","ClassB","SemsterA","SemesterB"};
var data =_db.Logs.Where(p=>(p.SDate.Date >= CDate.Date && p.SDate.Date <= FDate.Date)&&startingKeys.Any(k=>p.Logs.StartsWith(k))).GroupBy(p=>startingKeys.Where(k=>p.Logs.StartsWith(k)).First(),(key,items)=>new {source=key,count = items.Count()})
One advantage of this method is you can change the starting keys at runtime if you feel like it.

Convert SQL to LINQ with group by

I'm stumped trying to convert the following sql to linq:
SELECT t.* FROM(SELECT mwfieldid,MAX([TimeStamp]) AS MaxValue, BatchDocumentID
FROM mw_BatchField
GROUP BY mwfieldid,BatchDocumentID) x
JOIN mw_BatchField t ON x.mwfieldid = t.mwfieldid
AND x.MaxValue = t.TimeStamp
and x.BatchDocumentID = t.BatchDocumentID
So far I had to convert it to a stored proc to get it to work. I'd rather know how to write this correctly in linq. I tried using a sql to linq converter (http://www.sqltolinq.com/) which produced this code that had errors in it: (Are these converters any good? It didn't seem to produce anything useful with a few tries.)
From x In (
(From mw_BatchFields In db.mw_BatchFields
Group mw_BatchFields By
mw_BatchFields.MWFieldID,
mw_BatchFields.BatchDocumentID
Into g = Group
Select
MWFieldID,
MaxValue = CType(g.Max(Function(p) p.TimeStamp),DateTime?),
BatchDocumentID)
)
Join t In db.mw_BatchFields
On New With { .MWFieldID = CInt(x.MWFieldID), .MaxValue = CDate(x.MaxValue), .BatchDocumentID = CInt(x.BatchDocumentID) }
Equals New With { .MWFieldID = t.MWFieldID, .MaxValue = t.TimeStamp, .BatchDocumentID = t.BatchDocumentID }
Select
BatchFieldID = t.BatchFieldID,
BatchDocumentID = t.BatchDocumentID,
MWFieldID = t.MWFieldID,
TimeStamp = t.TimeStamp,
value = t.value,
DictionaryValue = t.DictionaryValue,
AutoFilled = t.AutoFilled,
employeeID = t.employeeID
Seems like a lot of code for such a simple query, and it doesn't compile.
So for every combination of mwfieldid and BatchDocumentID you want all columns of the row with the highest TimeStamp? This is something which is much easier to express in LINQ than SQL so I'm not surprised that an automated converter is making a meal of it.
You should be able to do:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.SelectMany(x => x.Where(y => y.TimeStamp == x.Max(z => z.TimeStamp)))
This (like your SQL) will return multiple rows per grouping key if there is more than one row in the group that shares the same maximum TimeStamp. If you only want row per key, you could use:
Mw_BatchFields.GroupBy(x => new { x.Mwfieldid, x.BatchDocumentId })
.Select(x => x.OrderByDescending(y => y.TimeStamp).First())
Edit:
Sorry, just twigged that you're working in VB, not C#, so not quite what you were looking for, but if you can live with the lambda syntax style, I think the above can be translated as:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).Select(Function(x) x.OrderByDescending(Function(y) y.TimeStamp).First())
and:
Mw_BatchFields.GroupBy(Function(x) New With {x.Mwfieldid, x.BatchDocumentId}).SelectMany(Function(x) x.Where(Function(y) y.TimeStamp = x.Max(Function(z) z.TimeStamp)))

Entity Framework and dynamic order by statements

I have been struggling to get this working. I wish to have an EF statement take in a column to order by. My original statement was this:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
And I changed this to the following:
var Query = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby sortField
select P;
Where sortField is the column we wish to sort on, and is a string i.e. LastName. However, it does not appear to work, it does no sorting, and the outputted SQL string is completely wrong. Anyone got this working before?
you could try passing in an expression to your method with the following type:
Expression<Func<Person, object>> expr = p => p.LastName;
and then using linq extensions instead of linq expressions...
var Query =
DbContext.People
.Where(P => P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId))
.OrderBy(expr)
.ToList();
Your sort does not work because you are sorting on a string literal. It is not illegal, but it is not particularly useful either. You need to provide a sorting field through the API of IQueryable<T>, for example, like this:
var q = from P in DbContext.People
where P.BusinessUnits.Any(BU =>BU.BusinessUnitID == businessUnitId)
orderby P.LastName
select P;
if ("sortField".Equals("FirstName"))
q = q.OrderBy(p => p.FirstName);
else if ("sortField".Equals("LastName"))
q = q.OrderBy(p => p.LastName);
else if ("sortField".Equals("Dob"))
q = q.OrderBy(p => p.Dob);