Get formatted date in string format in LINQ to Entities - c#

I am using the following LINQ to Entities code for getting data from a database table named Stocks:
IEnumerable<DrugInfoViewModel> Info = from a in db.Stocks.Where(
r => r.SiteID == SiteID
&& r.MachineID == MachineID
&& EntityFunctions.TruncateTime(r.ExpiryDate) <= ExpiryDate)
select new DrugInfoViewModel()
{
ItemName = a.DrugBrand.Name,
ItemBatchNo = a.BatchNo,
ItemExpiryDate = (a.ExpiryDate == null ? null :
Convert.ToDateTime(a.ExpiryDate).ToString("MM/dd/yyyy")),
Quantity = (int?)a.Qty
};
Here, ItemExpiryDate is a string field and a.ExpiryDate is a nullable datetime field in the table. When I run this code I am getting this error:
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
This same line of code works properly in another page. Why is this happening?

Just add ToList() or ToArray() method after Where(). This will fetch filtered objects to your memory and you will be able to call ToString(). Please, make sure that you call ToList() after filtering to avoid fetching all of the records from the table.
IEnumerable<DrugInfoViewModel> Info = from a in db.Stocks.Where(
r => r.SiteID == SiteID
&& r.MachineID == MachineID
&& EntityFunctions.TruncateTime(r.ExpiryDate) <= ExpiryDate)
.ToList()
select new DrugInfoViewModel()
{
ItemName = a.DrugBrand.Name,
ItemBatchNo = a.BatchNo,
ItemExpiryDate = (a.ExpiryDate == null ? null :
Convert.ToDateTime(a.ExpiryDate).ToString("MM/dd/yyyy")),
Quantity = (int?)a.Qty
};

This happens because the LINQ expression is evaluated on the server side i.e. inside SQL Server and there the function ToString() is not available.
As suggested in the comments already: Get a DateTime, format on the client side.

Related

How to factorize a Linq request with multiple includes?

My model has:
Several DeviceStatus attached to one mandatory Device
SeveralDevice attached to one mandatory Panel
When I query DeviceStatus, I need to have Device and Panel attached to it in the query result.
... DeviceStatus.Device is null in the query result.
Here is the Linq Query:
using (var actiContext = new ActigraphyContext())
{
var todayStatus =
from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel)
where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
&& s.Device.Panel.Mac == mac
&& (s.Device.Ty == 4 || s.Device.Ty == 9)
select s;
// var tempList = todayStatus.toList();
var todayLastStatus =
from s in todayStatus.Include(s1 => s1.Device.Panel)
let lastTimeStamp = todayStatus.Max(s1 => s1.TimeStamp)
where s.TimeStamp == lastTimeStamp
select s;
var requestResult = todayLastStatus.FirstOrDefault();
return requestResult;
}
If I uncomment the line // var tempList = todayStatus.toList();, where tempList is not used, it works: requestResult.Device is set!
But the bad side is todayStatus.toList triggers a request that brings a huge amount of data.
So how to get the DeviceStatus with its relative objects ?
Note: the database behind is SQL Server 2012
When you call an Include() over a LINQ query, it performs Eagerly Loading.
As documented in MSDN:
Eager loading is the process whereby a query for one type of entity also loads related entities as part of the query. Eager loading is achieved by use of the Include method.
When the entity is read, related data is retrieved along with it. This typically results in a single join query that retrieves all of the data that's needed. You specify eager loading by using the Include method.
So you need to call the .toList() to complete the query execution.
Since the data is huge, you can pickup relative specific columns as per your requirement by using the Select clause.
var todayStatus =
from s in actiContext.DeviceStatus
.Include(s1 => s1.Device.Panel.Select(d => new
{
d.DeviceId,
d.DeviceName,
d.PanelID
}))
where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
&& s.Device.Panel.Mac == mac
&& (s.Device.Ty == 4 || s.Device.Ty == 9)
select s;
var tempList = todayStatus.toList();
The query doesn't actually run until you do a call like ToList(), which is why uncommenting that line works. If the query is bringing back too much data, then you need to change the query to narrow down the amount of data you're bringing back.
Ok this request is a more simple way to achieve this:
using (var actiContext = new ActigraphyContext())
{
var todayLastStatus =
from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel)
where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime( DateTimeOffset.Now)
&& s.Device.Panel.Mac == mac
&& (s.Device.Ty == 4 || s.Device.Ty == 9)
orderby s.TimeStamp descending
select s;
var requestResult = todayLastStatus.Take(1).FirstOrDefault();
return requestResult;
}
But the question remains: why didn't I get the relative object in my first request ?

Search for null field in Linq query

Using T-SQL in SQL Server Management Studio this query returns exactly what I am expecting
SELECT * FROM ZipCodeTerritory WHERE ZipCode IS NULL and StateCode = 'WA'
However... the following Linq query returns no results. I've checked the connection string and I have verified I'm connecting to the database. Using a value for the cleanZip variable will return a list. Using a null value, however, never returns anything.
string cleanZip = (item.ToUpper().Equals("NULL") ? null : item.Trim());
var zipCodes = (from z in db.ZipCodeTerritory
where z.ZipCode.Equals(cleanZip) && z.StateCode.Equals(searchState)
select z).ToList();
Changed the query to the following and it is working now.
var zipCodes = (from z in db.ZipCodeTerritory
where (cleanZip == null ? z.ZipCode.Equals(null) : z.ZipCode.Equals(cleanZip)) && z.StateCode.Equals(searchState)
select z).ToList();

Entity Framework Error Trying to Get Row Count in Linq to Entities

When I try to run this code:
var qry = ( from v in db.Visits
where v.VisitorID == visitorID
&& v.IncomingID == incomingID
&& v.ProjectID == ProjectID.GetID()
select v.VisitorID);
int visits = qry.Count();
The qry runs okay but the "int visits = ..." line bombs out with "LINQ to Entities does not recognize the method 'Int32 GetID()' method, and this method cannot be translated into a store expression."
What am I doing wrong?
what you are doing wrong, is that ProjectID.GetID() can not be called in linq to entity, you can call this before your query:
var o = ProjectID.GetID();
var qry = (from v in db.Visits
where v.VisitorID == visitorID &&
v.IncomingID == incomingID &&
v.ProjectID == o
select v.VisitorID);
int visits = qry.Count();
You can't call custom methods in a query like this.
LINQ to Entities works by building an expression tree in order to convert to a database query.
It sees ProjectID.GetID() and it has no idea how to translate that into SQL.

GetBytes method cannot be translated into a store expression

I am using LINQ to select a list based on a particular condition. The attribute value is stored in byte array, which is later encrypted while storing in the database table. I want to using this attribute in my SELECT LINQ query now, but it is throwing the following exception when I try to:
LINQ to Entities does not recognize the method 'Byte[] GetBytes(System.String)' method, and this method cannot be translated into a store expression.
This is the code that I using:
var result = (from history in context.Histories
where history.ID == Id &
(history.Salary != null || history.Salary != Encoding.ASCII.GetBytes("0"))
select (DateTime?)history.Date).Max();
return result;
I want to select the date from the history table, of those id's whose salary is either not equal to null or 0. How can I change this?
Just get the bytes first :
var bytes = Encoding.ASCII.GetBytes("0");
var result = (from history in context.Histories
where history.ID == Id &
(history.Salary != null || history.Salary != bytes)
select (DateTime?)history.Date).Max();
return result;
Change your code to:
var bytes = Encoding.ASCII.GetBytes("0");
var result = (from history in context.Histories
where history.ID == Id &
(history.Salary != null || history.Salary != bytes)
select (DateTime?)history.Date).Max();
return result;
LINQ can't evaluate your GetBytes when it translates your query to SQL

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.

Categories

Resources