Have a OData Web Service that I want to query and apply conditional processing to but the following error is being recieved "Error translating Linq expression to URI: Can only specify query options (orderby, where, take, skip) after last navigation"
var reason = (from x in odataContainer.Table where x.userId == "test" select x.eventReason );
if (eventReason == "Failure")
// Do something
The query does work if I don't make the selection specific i.e select x instead of x.eventReason however I want to avoid pulling back a lot of data by applying a filter.
Any suggestions on how to make this work?
Try this,
var reason = odataContainer.Table.Where(x => x.UserId == "test").FirstOrDefault().eventReason;
This should work!
Related
So I´m having a problem with a query im trying to do. I´m trying to get the last element of a list in a linq query in c# using ef.
Here is the code im trying to execute:
public List<Viagem> getViagensToBeCompletedInBlocoTrabalho()
{
return this.context.Viagens
.Where(v => v.blocosTrabalho.Count() == 0
|| !v.blocosTrabalho.LastOrDefault().noFim.Equals(v.horasPassagem.LastOrDefault().codigoNo)
)
.ToList();
}
But i get this error: Queries performing 'LastOrDefault' operation must have a deterministic sort order. Rewrite the query to apply an 'OrderBy' clause on the sequence before calling 'LastOrDefault'.
What am i doing wrong here?
By the way the sorting that i want is the order of entries in the table so i don´t really want to sort anything. Although i have also tested sorting and it doesn´t work.
Thanks for the help in advance :-)
Actually SQL standard do not support retrieving records from the end and even do not guarantee records in concrete order. EF is trying to simulate that by correcting OrderBy operator and if you do not specify that - it will fail.
Consider to rewrite your query and make it performant:
public List<Viagem> getViagensToBeCompletedInBlocoTrabalho()
{
var query =
from v in this.context.Viagens
from b in v.blocosTrabalho.OrderByDescending(x => x.Id)
.Take(1).DefaultIfEmpty()
from h in v.horasPassagem.OrderByDescending(x => x.Id)
.Take(1).DefaultIfEmpty()
where
b == null || b != null && b.noFim == h.codigoNo
select v;
return query.ToList();
}
I have a StudentReceipts table which stores ReceiptNo as string(001,002,003,..,099,..).
I want go get the last receiptno details inorder to increment the receiptno for next transaction.
This is what I have tried
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable()
.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
But there i am getting the following exception
this function can only be invoked from linq to entities
Any help will be highly appreciated.
By calling .AsEnumerable() you are going from Linq-To-Entities to Linq-To-Object. By calling it, you are also filtering all the results in memory, so you are pulling the whole StudentReceipts table from the database everytime you do that query as it gets executed past the .AsEnumerable() method. The general rule is to try to do as much as you can on the database side:
var _lastGeneratedRecDetails =
_db.StudentReceipts.Where(r => r.Status == true
&& EntityFunctions.TruncateTime(r.DueDate.Value) >= _startDate.Date
&& EntityFunctions.TruncateTime(r.DueDate.Value) <= _endDate.Date)
.AsEnumerable()
.OrderByDescending(x => Int32.Parse(x.ReceiptNo))
.FirstOrDefault();
If you do it like this, you will filter everything in the database and fetch the filtered results. I don't know what type x.ReceiptNo is though, but calling Int.Parse isn't allowed in Linq-To-Entities. You can filter first and then call AsEnumerable to be able to do the parsing and ordering in memory.
In my case, I was re-using a Func / Filter expression that included DbFunctions.TruncateTime in a follow-up processing statement AFTER I had already processed the query in SQL. Removing it cleared the instance of the exception for me.
use and
.AsQueryable()
var _lastGeneratedRecDetails = _db.StudentReceipts
.AsEnumerable().AsQueryable()
I'm generating a query using Entity Framework which uses a group by clause and then attempts to order each of the groups to get specific data. I attempted to optimize the order by to only happen once using a let statement but the results are incorrect but the query still executes.
Concept:
var results =
(from n in noteEntities.NoteLog
where associatedIDs.Contains(n.AssociatedID)
group n by n.AssociatedID into gn
let ogn = gn.OrderByDescending(t => t.CreatedDateTime)
let successNote = ogn.FirstOrDefault(x => x.Type == "Success")
let lastStatusNote = ogn.FirstOrDefault()
select new { Success = successNote, Status = lastStatusNote, AssociatedID = gn.Key }).ToList();
However, the problem is that using, what should be the ordered let variable, ogn in the subsequent let statements is not using an order by descending list and I'm getting the wrong success and status notes. I've also tried changing things up to create a sub-query and reference the result but that doesn't seem to return an ordered list either, ex:
var subQuery =
(from n in noteEntities.NoteLog
where associatedIDs.Contains(n.AssociatedID)
group n by n.AssociatedID into gn
select gn.OrderByDescending(t => t.CreatedDateTime));
var results =
(from s in subQuery
let successNote = s.FirstOrDefault(x => x.Type == "Success")
let lastStatusNote = s.FirstOrDefault()
select new { Success = successNote, Status = lastStatusNote }).ToList();
I can make this work by using OrderByDescending twice in the select statement or let statements for the success and status notes but this becomes very slow, and redundant, when there are a lot of notes. Is there a way to run the order by only once and get the right results back?
In SQL a subquery with Order By must have a TOP statement (yours does not). And when Linq detects that there is no FirstOrDefault or Takestatements with the ordered subquery it just strips the OrderByDescending.
If you are having a performance problem with the query perhaps you should look into indexing the table.
I currently have a method on my repository like this:
public int GetMessageCountBy_Username(string username, bool sent)
{
var query = _dataContext.Messages.AsQueryable();
if (sent)
query = query.Where(x => x.Sender.ToLower() == username.ToLower());
else
query = query.Where(x => x.Recipient.ToLower() == username.ToLower());
return query.Count();
}
It currently builds one of two queries based on the sent boolean. Is this the best way to do this or is there a way to do this within the query itself? I want to check if x.Sender is equal to username if sent equals true. But I want to check if x.Recipient is equal to username if sent equals false.
I then want this LINQ expression to translate into SQL within Entity Framework, which I believe it is doing.
I just want to avoid repeating as much code as possible.
You could do something like this :
public int GetMessageCountBy_Username(string username, bool sent)
{
Func<Message, string> userSelector = m => sent ? m.Sender : m.Recipient;
var query =
_dataContext.Messages.AsQueryable()
.Where(x => userSelector(x).ToLower() == username.ToLower());
return query.Count();
}
Thus the choosing of the right user (the sender or the recipient) is done before the linq part, saving you from repeating it twice.
Yes, I believe this is correct way to do it. Because it is easy to create complex queries without repeating whole parts of queries.
And your thinking about translating to SQL is correct too. But beware, this is done at the moment, when data or agregation is requested. In your case, the SQL will be generated and executed when you call Count().
OK, first off, I'm brand new to LINQ2SQL so excuse my ignorance.
I've done some searches, but after 1 hour, I decided to come here.
Here goes:
I'm trying to do something that I think is very simple. It could just be that I don't understand. I'm using LINQ 2 SQL, via the VS designer. I have 2 tables: Clients and Categories. A client can have multiple categories.
I have a very simple query to find clients:
Client c = db.Clients.SingleOrDefault(client => client.ID == id);
What I want to do is modify this so that the collection: c.Categories, will only contain a subset of that client's categories.
This is what I've tried:
Client c = db.Categories.Where(cat => cat.IsActive == true).Select(cat.Clients).SingleOrDefault(client => client.ID == id);
I get an error reporting that more than one client is being returned.
Am I missing something? Is this not something that LINQ is designed to do?
Am I supposed to use the first query then do another query specifically on Categories when I need that list??
c.Categories.Categories.Where(cat => cat.IsActive == true)
Thank you in advance.
SingleOrDefault() is for when there's ONLY one result. It seems like there's more than one record that has that id. Try using FirstOrDefault() instead.
Client c = db.Categories.Where(cat => cat.Name == "Name").Select(cat.Clients).FirstOrDefault(client => client.ID == id);
The problem is that the Categories.Where part in combination with the Select, is returning a collection of collections. What you may need to do is either use SelectMany, or use Single (or SingleOrDefault, or First or FirstOrDefault) instead of Where.
Examples:
Client c = db.Categories.Where(cat => cat.IsActive)
.SelectMany(cat.Clients)
.SingleOrDefault(client => client.ID == id);
or
Client c = db.Categories.Single(cat => cat.IsActive)
.Clients
.SingleOrDefault(client => client.ID == id);