WCF RIA - Query operator 'Count' is not supported - c#

I'm trying the following code..
LoadOperation<Tasks> PhasesLP = context.
Load(context.GetTasksQuery().
Where(o=> ProjectList.Where(p=> p.ProjectID == o.ProjectID).Count() == 1)
I get the following error:
Query operator 'Count' is not supported.
I want to basically be able to specify a Where In clause instead of Where =.
Anyone has an idea of how I can achieve this?

Have you tried:
.SingleOrDefault() != null
I'm not familiar with RIA, but sometimes these kinds of alternate equivalent expressions work with EF.
Also, with EF, it's possible to do a SQL-style WHERE IN (...) using .Any(...).
Off the top of my head, this kind of thing works:
entities.Where(e => ids.Any(i => e.Id == i))
ids may be a list of IDs, another list of entities or a subquery, IIRC.

Related

Use skip and take inside a LINQ include

I have an object that has a property which is a collection of another object. I would like to load just a subset of the collection property using LINQ.
Here's how I'm trying to do it:
manager = db.Managers
.Include(m => m.Transactions.Skip((page - 1) * 10).Take(10))
.Where(m => m.Id == id)
.FirstOrDefault();
The code above throws an error that says
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.\r\nParameter name: path
What is the right way to do this in LINQ? Thanks in advance.
You cannot do this with Include. EF simply doesn't know how to translate that to SQL. But you can do something similar with sub-query.
manager = db.Managers
.Where(m => m.Id == id)
.Select(m => new { Manager = m,
Transactions = db.Transactions
.Where(t=>t.ManagerId == m.Id)
.Skip((page-1) * 10)
.Take(10)})
.FirstOrDefault();
This will not return instance of Manager class. But it should be easy to modify it to suit your needs.
Also you have two other options:
Load all transactions and then filter in memory. Of course if there are a lot of transactions this might be quite inefficient.
Don't be afraid to make 2 queries in database. This is prime example when that is probably the best route, and will probably be the most efficient way of doing it.
Either way, if you are concerned with performance at all I would advise you to test all 3 approaches and see what is the fastest. And please let us know what were the results!
Sometimes the added complexity of putting everything in a single query is not worth it. I would split this up into two separate queries:
var manager = db.Managers.SingleOrDefault(m => m.Id == id);
var transactions = db.Transactions
.Where(t => t.ManagerId == id)
// .OrderBy(...)
.Skip((page - 1) * 10).Take(10)
.ToList();
Note that after doing this, manager.Transactions can be used as well to refer to those just-loaded transactions: Entity Framework automatically links loaded entities as long as they're loaded into the same context. Just make sure lazy loading is disabled, to prevent EF from automatically pulling in all other transactions that you specifically tried to filter out.

Searching Multiple Fields with LINQ Contains or Other

I'm using LINQ to search multiple fields on a single phrase and I'm using Contains() to do this. Up until today, when I noticed that the find method isn't working correctly.
So I'd like to be able to search each of the fields where there is any match. I've done some searching on Google and through SO and found suggestions of using Any()? Does anyone have any suggestions?
var l = _getData().Select(_marshallData).ToList();
return l.Where(x => x.Name.Contains(what) || x.Pumpkin.Contains(what) || x.Orange.Contains(what) || x.Tomato.Contains(what)).ToList();
Please excuse the stupid field names, I've had to change them for confidentiality.
Since you're materializing the data already you could do this:
var l = _getData().Select(_marshallData).AsEnumerable();
return l.Where(x => new[] { x.Name, x.Pumpkin, x.Orange, x.Tomato }.Any(s => s.Contains(what)));
But if you're using an ORM (like Entity Framework) this trick probably won't work (since there's a good chance this can't be converted to a SQL expression). In this case, you're original solution is fine, but it would probably be better to do this before you materialize the data.
return _getData()
.Where(x =>
x.Name.Contains(what) || x.Pumpkin.Contains(what) ||
x.Orange.Contains(what) || x.Tomato.Contains(what))
.Select(_marshallData)
.AsEnumerable();
Of course the field names here might be different, since the parameter x is probably a different type. Without further information, it's up to you to write this filter correctly.
Note that in both examples, I've eliminated the calls to ToList. Unless you absolutely need the result to a List<T> this is probably unnecessary.

Linq to Entities over EF 4 on SQL Server 2005

'Cannot compare elements of type 'System.Collections.Generic.ICollection`1'. Only primitive types (such as Int32, String, and Guid) and entity types are supported.'
Entities & Relationships (Navigation Properties):
Case (1 <-> ∞) MeetingCase (1 <-> ∞) MeetingCaseOutcomes
The offending code is:
IQueryable<Case> cases; // this is obviously attached to a context and able to access data)
var broken = cases
.Where(c => c.MeetingCases
.Where(mc => mc.ExpectedStartDateTime <= DateTime.Now)
.Any(m => m.MeetingCaseOutcomes == null || m.MeetingCaseOutcomes.Count == 0));
I assume the problem is due to lack of support for the 'Any' operator, though I had thought this would work in EF 4 (since support for the related 'Contains' operator has been added).
How should I re-structure this call to produce what I want?
I have been working with EF for several months now and understand many of the runtime gotchas
UPDATE:
The Where clause above does contain a predicate, as follows:
c.MeetingCases.Where(mc => mc.ExpectedStartDateTime <= DateTime.Now)
.Any(m => m.MeetingCaseOutcomes == null || m.MeetingCaseOutcomes.Count == 0)
Because Any returns a boolean, the whole thing produces a predicate expression.
Also, the intent of this logic is to return a set of Case objects which do not have MeetingCaseOutcome records for any MeetingCase records where the meeting has already taken place (hence the comparison to DateTime.Now). This is part of a meeting scheduling system, and this is to check that Outcomes from each meeting are entered into the system following the meeting taking place.
EF 1 and EF 4 both support .Any(). The problem is that you're not using it enough. :)
IQueryable<Case> cases; // this is obviously attached to a context and able to access data)
var broken = cases
.Where(c => c.MeetingCases
.Where(mc => mc.ExpectedStartDateTime <= DateTime.Now)
.Any(m => !m.MeetingCaseOutcomes.Any()));
This part is the problem:
Where(c => c.MeetingCases
.Where..
.Where requires a Expression<Func<T,bool>>, in otherwords a predicate which returns true/false. But your supplying it a predicate which returns a sequence of elements.
I think that second .Where needs to be changed to .Any or .All.
I'm struggling to decipher what query your attempting to execute, but i'm assuming you want a list of Case where at least one associated MeetingCase has a ExpectedStartDateTime before today.
So your query should be:
var cases = cases
.Where(case => case.MeetingCases
.Any(caseMeeting => caseMeeting.ExpectedStartDateTime <= DateTime.Now));
I'm not sure what your trying to do with that last .Any clause.
Also - don't forget about eager-loading/projection problems. You say "it's attached to the context", which is fine - but c.MeetingCases will not return anything unless you have lazy loading on or are eager loading beforehand.

LINQ to Entities: Using DateTime.AddMonth in Lambda Expression

I've been reading some posts but I don't find a solution to a problem that I have with LINQ To Entities, Lambda Expressions and DateTime.AddMonth.
The problem is that I'm trying to use DateTime.AddMonth inside a Lambda Expression and I'm getting this error:
"LINQ to Entities does not recognize the method 'System.DateTime
AddMonths(Int32)' method, and this method cannot be translated into a
store expression"
when I execute this piece of code:
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.Where(o => o.PaymentDate.Value.AddMonths(o.Products.ProductCategories.CommissionableMonths) > DateTime.Now)
.ToList();
Is there a way to avoid this exception but mantaining the same behavior?
I don't know a lot about Linq, Lambdas or Entity Framework.
Thank you very much in advance!
Gsus.
You could return the necessary information without filtering on the date, then filter on the date afterward. (Of course, I'm not sure what size your data will be, so this may be inefficient. If so, you'll need a SQL-based solution of some sort -- maybe a stored procedure.)
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.ToList();
orders = orders.Where(o.PaymentDate.Value.AddMonths(o.Products.ProductCategories.CommissionableMonths) > DateTime.Now);
This turns the AddMonths portion of the query in to a Linq-to-Objects method instead of Linq-to-Entities call.
try this,
var today =DateTime.Now;
List<Orders> orders = context.Orders
.Where(o => o.IdOrderStatus == 1)
.Where(o => SqlFunctions.DateAdd("month" ,o.Products.ProductCategories.CommissionableMonths,o.PaymentDate) > today)
.ToList();
LINQ to Entities converts your linq expression into SQL code, sometimes this conversion is seamless such as integer addition, selects, groups, etc, but sometimes the abstraction leaks, as in date operations.

Conditional shortcuts in LinqToSql query

Here's a little LinqToSql GOTCHA:
// Returns the number of counties in a state,
// or all counties in the USA if the state is null
public static int CountCounties(State s) {
var q =
from cy in County.GetTable() // my method to get the ITable
where (s == null || s.Code == cy.StateCode) // shortcut OR operator, right...?
select cy;
return q.Count();
}
Guess what - if you pass a null State object to this method, you get a null reference exception! It seems that LinqToSql doesn't use the || shortcut operator as a shortcut!
Answer credit goes to whoever proposes the best explanation & workaround for this.
If it's linq to sql then remeber that Linq is just parsing your query into SQL.
It is therefore sending both of your where clauses to the database, hence the exception. I dont find this surprising really, though it is arguably wrong.
You will just have to do an independant check.
if (!string.isNullOrEmpty(state.statecode)
q = q.where( s => s.code == state.statecode
This is not related to LINQ in general. In this case, the LINQ-to-SQL provider tries to parse the your lambda expression and make it a TSQL query. It cannot make too many assumptions based on your expression since it's trying to delegate most of the work to the database.
Long story short, the provider simply cannot translate it to SQL.

Categories