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

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.

Related

C# LINQ: DbFunctions.TruncateTime throw error This function can only be invoked from LINQ to Entities

here is my code.
List<NPSEntity> Data = null; ;
using (var db = new NPSDbContext())
{
Data = (from n in db.NPSDatas
orderby n.AddDate, n.CountryCode
where DbFunctions.TruncateTime(n.NPSDate) >= StartDate.Date && DbFunctions.TruncateTime(n.NPSDate) <= EndDate
select n).ToList();
}
NPSData = Data.Select(n => new NPSEntity
{
NPSDate = DbFunctions.TruncateTime(n.NPSDate),
NPSAmount = n.NPSAmount,
AddDate = n.AddDate,
ModDate = n.ModDate,
UserID = n.UserID,
CountryCode = n.CountryCode
}).ToList();
if (NPSData!=null)
{
CountryCodes = NPSData.Select(e => e.CountryCode).Distinct();
CountryCount = CountryCodes.Count();
}
this line throwing error NPSDate = DbFunctions.TruncateTime(n.NPSDate), This function can only be invoked from LINQ to Entities
my objective is to remove time portion from NPSDate NPSDate = DbFunctions.TruncateTime(n.NPSDate) that is why i used DbFunctions.TruncateTime function.
tell me how could i fix this problem or tell me how could i remove time portion from NPSDate when fetching data from db. my NPSDate property look like public DateTime? NPSDate { get; set; } that is why i can not use NPSDate.Date
please guide me. thanks
The error is self explanatory enough, that you cannot use DbFunctions in any other context, the context should only be Linq to Entities and when you call ToList() on an IQueryable<T>, the query gets executed and results are brought in memory, you would need to use Date property of DateTime if truncating the time is needed here like:
NPSData = Data.Select(n => new NPSEntity
{
NPSDate = n.NPSDate.Date,

Get formatted date in string format in LINQ to Entities

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.

Using Intersect I'm getting a Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator

I'm using a Linq to SQL query to provide a list of search term matches against a database field. The search terms are an in memory string array. Specifically, I'm using an "intersect" within the Linq query, comparing the search terms with a database field "Description". In the below code, the description field is iss.description. The description field is separated into an array within the Linq query and the intersect is used to compare the search terms and description term to keep all of the comparing and conditions within the Linq query so that the database is not taxed. In my research, trying o overcome the problem, I have found that the use of an in-memory, or "local" sequence is not supported. I have also tried a few suggestions during my research, like using "AsEnumerable" or "AsQueryable" without success.
searchText = searchText.ToUpper();
var searchTerms = searchText.Split(' ');
var issuesList1 = (
from iss in DatabaseConnection.CustomerIssues
let desc = iss.Description.ToUpper().Split(' ')
let count = desc.Intersect(searchTerms).Count()
where desc.Intersect(searchTerms).Count() > 0
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SearchHits = count,
SolutionDesc = (solution.Description == null)? "No Solutions":solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null)? false : stTois.Successful
}).ToList();
...
The only way I have been successful is to create two queries and calling a method as shown below, but this requires the Linq Query to return all of the matching results (with the number of hits for search terms in the description) including the non-matched records and provide an in-memory List<> and then use another Linq Query to filter out the non-matched records.
public static int CountHits(string[] searchTerms, string Description)
{
int hits = 0;
foreach (string item in searchTerms)
{
if (Description.ToUpper().Contains(item.Trim().ToUpper())) hits++;
}
return hits;
}
public static List<IssuesAndSolutions> SearchIssuesAndSolutions(string searchText)
{
using (BYCNCDatabaseDataContext DatabaseConnection = new BYCNCDatabaseDataContext())
{
searchText = searchText.ToUpper();
var searchTerms = searchText.Split(' ');
var issuesList1 = (
from iss in DatabaseConnection.CustomerIssues
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SearchHits = CountHits(searchTerms, iss.Description),
SolutionDesc = (solution.Description == null)? "No Solutions":solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null)? false : stTois.Successful
}).ToList();
var issuesList = (
from iss in issuesList1
where iss.SearchHits > 0
select iss).ToList();
...
I would be comfortable with two Linq Queries, but with the first Linq Query only returning the matched records and then maybe using a second, maybe lambda expression to order them, but my trials have not been successful.
Any help would be most appreciated.
Ok, so after more searching more techniques, and trying user1010609's technique, I managed to get it working after an almost complete rewrite. The following code first provides a flat record query with all of the information I am searching, then a new list is formed with the filtered information compared against the search terms (counting the hits of each search term for ordering by relevance). I was careful not to return a list of the flat file so there would be some efficiency in the final database retrieval (during the formation of the filtered List<>). I am positive this is not even close to being an efficient method, but it works. I am eager to see more and unique techniques to solving this type of problem. Thanks!
searchText = searchText.ToUpper();
List<string> searchTerms = searchText.Split(' ').ToList();
var allIssues =
from iss in DatabaseConnection.CustomerIssues
join stoi in DatabaseConnection.SolutionToIssues on iss.IssueID equals stoi.IssueID into stoiToiss
from stTois in stoiToiss.DefaultIfEmpty()
join solJoin in DatabaseConnection.Solutions on stTois.SolutionID equals solJoin.SolutionID into solutionJoin
from solution in solutionJoin.DefaultIfEmpty()
select new IssuesAndSolutions
{
IssueID = iss.IssueID,
IssueDesc = iss.Description,
SolutionDesc = (solution.Description == null) ? "No Solutions" : solution.Description,
SolutionID = (solution.SolutionID == null) ? 0 : solution.SolutionID,
SolutionToIssueID = (stTois.SolutionToIssueID == null) ? 0 : stTois.SolutionToIssueID,
Successful = (stTois.Successful == null) ? false : stTois.Successful
};
List<IssuesAndSolutions> filteredIssues = new List<IssuesAndSolutions>();
foreach (var issue in allIssues)
{
int hits = 0;
foreach (var term in searchTerms)
{
if (issue.IssueDesc.ToUpper().Contains(term.Trim())) hits++;
}
if (hits > 0)
{
IssuesAndSolutions matchedIssue = new IssuesAndSolutions();
matchedIssue.IssueID = issue.IssueID;
matchedIssue.IssueDesc = issue.IssueDesc;
matchedIssue.SearchHits = hits;
matchedIssue.CustomerID = issue.CustomerID;
matchedIssue.AssemblyID = issue.AssemblyID;
matchedIssue.DateOfIssue = issue.DateOfIssue;
matchedIssue.DateOfResolution = issue.DateOfResolution;
matchedIssue.CostOFIssue = issue.CostOFIssue;
matchedIssue.ProductID = issue.ProductID;
filteredIssues.Add(matchedIssue);
}
}

LINQ to Entities does not recognize the method 'System.String get_Item (System.String)',

How can I solve this problem?
Here is my code:
DateTime dtInicio = new DateTime();
DateTime dtFim = new DateTime();
Int32 codStatus = 0;
if(!string.IsNullOrEmpty(collection["txtDtInicial"]))
dtInicio = Convert.ToDateTime(collection["txtDtInicial"]);
if(!string.IsNullOrEmpty(collection["txtDtFinal"]))
dtFim = Convert.ToDateTime(collection["txtDtFinal"]);
if (!string.IsNullOrEmpty(collection["StatusCliente"]))
Convert.ToInt32(collection["StatusCliente"]);
var listCLientResult = (from c in db.tbClientes
orderby c.id
where (c.effdt >= dtInicio || string.IsNullOrEmpty(collection["txtDtInicial"]) &&
(c.effdt <= dtFim || string.IsNullOrEmpty(collection["txtDtFinal"])) &&
(c.cod_status_viagem == codStatus || string.IsNullOrEmpty(collection["StatusCliente"])))
select c);
return View(listCLientResult);
The error I am getting is:
LINQ to Entities does not recognize the method 'System.String get_Item (System.String)', which can not be converted into an expression of the repository.
Linq queries performed against a database are translated to SQL before they can be executed; but collection["txtDtInicial"] can't be translated to SQL, because there is no equivalent SQL syntax, and anyway the database doesn't have access to collection. You need to extract collection["txtDtInicial"] to a variable first, and use only this variable in the query.
Here's what I would do:
DateTime dtInicio = DateTime.MinValue;
DateTime dtFim = DateTime.MaxValue;
Int32 codStatus = 0;
if(!string.IsNullOrEmpty(collection["txtDtInicial"]))
dtInicio = Convert.ToDateTime(collection["txtDtInicial"]);
if(!string.IsNullOrEmpty(collection["txtDtFinal"]))
dtFim = Convert.ToDateTime(collection["txtDtFinal"]);
if (!string.IsNullOrEmpty(collection["StatusCliente"]))
codStatus = Convert.ToInt32(collection["StatusCliente"]);
var listCLientResult = (from c in db.tbClientes
orderby c.id
where (c.effdt >= dtInicio) &&
(c.effdt <= dtFim) &&
(c.cod_status_viagem == codStatus)
select c);
return View(listCLientResult);
By initializing dtInicio and dtFim to MinValue and MaxValue, you don't need to check whether they are defined in the query.
The Linq query is ultimately transformed into an SQL query and LINQ doesn't know what to do with Session["UserName"] (that gets the "UserName" item).
A common way to workaround this is just to use a local variable to which you'll assign Session["UserName"] and that you'll use in your Linq query...
like
string loggedUserName = Session["LogedUsername"].ToString();
var userdetail =
dc.faculties.Where(a => a.F_UserName.Equals(loggedUserName)).FirstOrDefault();
reference http://mvc4asp.blogspot.in/
In one line...
DO NOT USE STRING CONVERSION FUNCTIONS in Linq(Entity) Query!
Wrong:
user = db.Users.Where(u => u.Name == dt.Rows[i]["Name"].ToString()).FirstOrDefault();
Correct:
string Name = dt.Rows[i]["Name"].ToString();
user = db.Users.Where(u => u.Name == Name).FirstOrDefault();

.NET: LINQ's Last()

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;

Categories

Resources