I have the following code:
var thing = (from t in things
where t.Type == 1 && t.IsActive
select t).SingleOrDefault();
if (thing == null)
{
// throw exception
}
things is a collection of Entity Framework Self-Tracking Entities
This works nicely, however I want to use a Lambda expression instead and changed the LINQ to this:
var thing = things.Select(t => t.Type == 1 && t.IsActive).SingleOrDefault();
Now Resharper is telling me Expression is always false for (thing == null).
What have I missed?
You want:
var thing = things.Where(t => t.Type == 1 && t.IsActive).SingleOrDefault();
Select performs a projection (converting the type of the IEnumerable from IEnumerable<Thing> to IEnumerable<bool> with values true if t.Type == 1 && t.IsActive == true, otherwise false), then the SingleOrDefault returns either the only bool in this sequence, or the default value of a bool which is false if the sequence is empty. This can never be null since bool is not a reference type.
Where performs a filtering action (pulling out only those objects that meet a given criterion - in this case only selecting those where Type is 1 and IsActive is true), leaving the type of the IEnumerable as IEnumerable<Thing>. Assuming Thing is a class, the SingleOrDefault will return the only item in the sequence or null.
In either case, SingleOrDefault will throw an exception if the sequence contains more than one item (which is far more likely in the Select version!).
Related
I have a method which return a List of Class object.
After getting the list I want to check whether a specific entry exists or not
Below is my query
var myList = GetMethod()
if(myList != null && myList.Select(x => x.Id=='MyId').Any())
{
// Do work
}
If the mylist is not null then myList.Select(x => x.Id=='MyId').Any() is always returning true even if a matching entry is not there.
Can someone help me in this?
That is because you need a Where over a Select:
if(myList != null && myList.Where(x => x.Id=='MyId').Any())
Now the Select ends up with an enumerable of booleans... Some are true, some are false.
You could simply that to:
if(myList != null && myList.Any(x => x.Id=='MyId'))
Select returns an IEnumerable of booleans whether the condition was true for each item or not. So, Any() is always returning true as long as there are items in your list.
Just use:
myList?.Any(x => x.Id == "MyId") == true;
Note that I don't like boolean comparisons like == true but this is for the null-check with ?. upfront.
I am using Visual Studio 2012 with MySQL 5.7 Community Edition. I am getting object reference not set to an instance of object on the below query.
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
}).ToList();
In the above query If I get change 12345678 to dm.DocumentHandle, then getting object reference not set to an instance object.
Try with MS-SQL server , working fine.
You get the error because FirstOrDefault() returns null, because there are no objects who's DocumentHandle equals dm.DocumentHandle. Changing dm.DocumentHandle to 12345678 works because there is one matching element.
This line is the problem:
.Where(x => x.DocumentHandle == 12345678).FirstOrDefault().Remarks
C#'s Enumerable.FirstOrDefault() method returns either the first matching element of an enumerable, or, if there aren't any, the default value of the type. In the case of nullable types, FirstOrDefault() returns null if no elements are found.
The reason you get no error when you use 12345678 is because there is at least one matching value with that DocumentHandle. However, when you change that to dm.DocumentHandle, no matching elements are found, causing FirstOrDefault to return null. Then you essentially do null.Remarks, which causes the error.
You should change your code to this:
.FirstOrDefault(x => x.DocumentHandle == dm.DocumentHandle)?.Remarks
There are two differences here:
Got rid of the where and moved the predicate to the FirstOrDefault call. This is just a cleaner way of doing what you were doing before.
Added the ? at the end of the FirstOrDefault call. That is the null propagation operator.
What it does is it turns this:
int foo;
if (bar != null)
{
foo = bar.foo;
}
Into this:
int foo = bar?.foo;
Now, if there are matching elements, statusRemarks will be equal to the first one's Remarks. Otherwise, statusRemarks will be null.
EDIT: The null propagation operator was implemented in C# 6.0, which is .Net 4.6 onwards, so it won't work in .Net 4.0.
You'll have to modify your query and implement a check, like so:
var oList = (
from dm in dbContext.document_master
join um in dbContext.user_master on dm.Alocated_CAA equals um.UserId
where (dm.DocumentHandle != null && dbContext.statushistories.Count(x => x.DocumentHandle == dm.DocumentHandle) > 0)
select new TaskLogReport
{
documentDate = dm.Document_Date,
documentHandle = dm.DocumentHandle,
fileNumber = dm.FileNumber,
statusRemarks = dbContext.statushistories.First(x.DocumentHandle == dm.DocumentHandle).Remarks
}).ToList();
Hi I have following linq statement
var list=(from c in db.sales
where c.id ==id && || c.name==name
select new model
{
//.....
});
I am having problem with my where clause.
Basically I can get id and name values or either one of them can be null. So I am trying to use where clause with AND OR meaning both condition could be right or either one.
With this where syntax i get intelliscence error. Please let me know how I can use AND OR check in the where clause.
both condition could be right or either one
You simply need or and do not need and
var list=(from c in db.sales
where c.id ==id || c.name==name
select new model
{
//.....
});
The || (or Operator)
The conditional-OR operator (||) performs a logical-OR of its bool
operands. If the first operand evaluates to true, the second operand
isn't evaluated. If the first operand evaluates to false, the second
operator determines whether the OR expression as a whole evaluates to
true or false, MSDN.
It sounds like what you want is just an ordinary OR:
where c.id == id || c.name == name
This will evaluate to true if c.id == id is true, if c.name == name is true, or if both are true.
I think you mean IntelliSense error. This is obvious, because && || is not valid C# syntax.
From what you describe, I think you only need the OR operation.
Try changing && || to just ||.
I want to filter a list with FindAll
If I write:
.FindAll(
p => p.Field == Value &&
p.otherObjList.Contains(otherObj));
it's ok, but if I write
.FindAll(
p => p.Field == Value &&
p.otherObjList.Contains(
q => q.Field1 == Value1 &&
q.Field2 == Value2));
I get C# syntax error message: Unknown Method FindAll(?) of .. the otherObjList
I cannot define the otherObj exactly, because I know only the values of two fields, Field1 and Field2.
What have I done wrong? What can I do in this case?
The Contains() method for both most collection types as well as the LINQ version expects an argument of the same type as the collection, not a lambda.
It appears you are just trying to check if any item matches some condition. You should use the Any() method.
.FindAll(p => p.Field == Value
&& p.otherObjList.Any(q => q.Field1 == Value1 && q.Field2 == Value2))
the problem in short
we have a lambda expression used in the Where clause, which is not returning the "expected" result.
quick summary
in the analysisObjectRepository object, there are certain objects which also contain the parent relationship in a property named Parent. we are querying this analysisObjectRepository to return some objects.
detail
what the code below supposed to do is, returning the root, the first children (immediate children) and grandchildren of a specific object containing the ID value.
in the code below, common sense says that all the results which makes any of the 3 seperate OR conditions true should be returned as in the results.
List<AnalysisObject> analysisObjects =
analysisObjectRepository
.FindAll()
.Where(x => x.ID == packageId ||
x.Parent.ID == packageId ||
x.Parent.Parent.ID == packageId)
.ToList();
but the above code only returns the children and grandchildren, while not returning the root objects (with a null Parent value) which make the
x.ID == packageId
condition true.
only objects which make the second
x.Parent.ID == packageId
and third
x.Parent.Parent.ID == packageId
clauses are returned.
If we only write the code to return the root object with the below code, it is returned, so we are totally sure that analysisObjectRepository contains all the objects
List<AnalysisObject> analysisObjects =
analysisObjectRepository
.FindAll()
.Where(x => x.ID == packageId )
.ToList();
However, when we rewrite it as a delegate, we get the expected result, returning all the expected objects.
List<AnalysisObject> analysisObjects =
analysisObjectRepository
.FindAll()
.Where(delegate(AnalysisObject x)
{
return
(x.ID == packageId) ||
(x.Parent != null && x.Parent.ID == packageId) ||
(x.Parent != null &&
x.Parent.Parent != null &&
x.Parent.Parent.ID == packageId); })
.ToList();
question
Are we missing something in the lambda expression? it is a really simple 3 part OR condition and we think that any object that makes any of the three conditions true should be returned. we suspected that the root object having a null Parent value might cause a problem but couldn't figure it out exactly.
any help would be great.
Your second delegate is not a rewrite of the first in anonymous delegate (rather than lambda) format. Look at your conditions.
First:
x.ID == packageId || x.Parent.ID == packageId || x.Parent.Parent.ID == packageId
Second:
(x.ID == packageId) || (x.Parent != null && x.Parent.ID == packageId) ||
(x.Parent != null && x.Parent.Parent != null && x.Parent.Parent.ID == packageId)
The call to the lambda would throw an exception for any x where the ID doesn't match and either the parent is null or doesn't match and the grandparent is null. Copy the null checks into the lambda and it should work correctly.
Edit after Comment to Question
If your original object is not a List<T>, then we have no way of knowing what the return type of FindAll() is, and whether or not this implements the IQueryable interface. If it does, then that likely explains the discrepancy. Because lambdas can be converted at compile time into an Expression<Func<T>> but anonymous delegates cannot, then you may be using the implementation of IQueryable when using the lambda version but LINQ-to-Objects when using the anonymous delegate version.
This would also explain why your lambda is not causing a NullReferenceException. If you were to pass that lambda expression to something that implements IEnumerable<T> but not IQueryable<T>, runtime evaluation of the lambda (which is no different from other methods, anonymous or not) would throw a NullReferenceException the first time it encountered an object where ID was not equal to the target and the parent or grandparent was null.
Added 3/16/2011 8:29AM EDT
Consider the following simple example:
IQueryable<MyObject> source = ...; // some object that implements IQueryable<MyObject>
var anonymousMethod = source.Where(delegate(MyObject o) { return o.Name == "Adam"; });
var expressionLambda = source.Where(o => o.Name == "Adam");
These two methods produce entirely different results.
The first query is the simple version. The anonymous method results in a delegate that's then passed to the IEnumerable<MyObject>.Where extension method, where the entire contents of source will be checked (manually in memory using ordinary compiled code) against your delegate. In other words, if you're familiar with iterator blocks in C#, it's something like doing this:
public IEnumerable<MyObject> MyWhere(IEnumerable<MyObject> dataSource, Func<MyObject, bool> predicate)
{
foreach(MyObject item in dataSource)
{
if(predicate(item)) yield return item;
}
}
The salient point here is that you're actually performing your filtering in memory on the client side. For example, if your source were some SQL ORM, there would be no WHERE clause in the query; the entire result set would be brought back to the client and filtered there.
The second query, which uses a lambda expression, is converted to an Expression<Func<MyObject, bool>> and uses the IQueryable<MyObject>.Where() extension method. This results in an object that is also typed as IQueryable<MyObject>. All of this works by then passing the expression to the underlying provider. This is why you aren't getting a NullReferenceException. It's entirely up to the query provider how to translate the expression (which, rather than being an actual compiled function that it can just call, is a representation of the logic of the expression using objects) into something it can use.
An easy way to see the distinction (or, at least, that there is) a distinction, would be to put a call to AsEnumerable() before your call to Where in the lambda version. This will force your code to use LINQ-to-Objects (meaning it operates on IEnumerable<T> like the anonymous delegate version, not IQueryable<T> like the lambda version currently does), and you'll get the exceptions as expected.
TL;DR Version
The long and the short of it is that your lambda expression is being translated into some kind of query against your data source, whereas the anonymous method version is evaluating the entire data source in memory. Whatever is doing the translating of your lambda into a query is not representing the logic that you're expecting, which is why it isn't producing the results you're expecting.
Try writting the lambda with the same conditions as the delegate. like this:
List<AnalysisObject> analysisObjects =
analysisObjectRepository.FindAll().Where(
(x =>
(x.ID == packageId)
|| (x.Parent != null && x.Parent.ID == packageId)
|| (x.Parent != null && x.Parent.Parent != null && x.Parent.Parent.ID == packageId)
).ToList();
You are checking Parent properties for null in your delegate. The same should work with lambda expressions too.
List<AnalysisObject> analysisObjects = analysisObjectRepository
.FindAll()
.Where(x =>
(x.ID == packageId) ||
(x.Parent != null &&
(x.Parent.ID == packageId ||
(x.Parent.Parent != null && x.Parent.Parent.ID == packageId)))
.ToList();