Linq statements, multiple where clauses - linq

I have this linq statement I just wrote:
Location loc = db.Locations.Where(l => l.name == name).Where(l => l.type == "SERV").FirstOrDefault();
I am wondering if this is how you do select from where and ... or if there is a better way to do this
I am trying to do select from locations name where the name is the name passed in and the type is the type passed in, get me the first location that matches this.

You do not need to chain Wheres - you can use && instead. Moreover, since FirstOrDefault takes a condition, you can move the entire clause inside the call, like this:
Location loc = db
.Locations
.FirstOrDefault(l => l.name == name && l.type == "SERV");

What you are doing will work just fine, but you can also just do this:
Location loc = db.Locations.Where(l => l.name == name && l.type == "SERV").FirstOrDefault();
UPDATE:
Since this is apparently going against a database object I was curious what the underlying SQL would look like in each case - my guess is they would be the same.
I used a ToTraceString() extension to view the SQL and just as expected, they are the same.

Related

Access a collection via LINQ and set a single member to a new object

I am trying to access a user object in a collection with the id = to users101 and set this to another users.
Controller.MyObject.SingleOrDefault(x => x.Id == "user101") = OtherUser();
Thanks in advance.
You can't do it with one LINQ expression.
Usually LINQ extensions works on enumerables, if MyObject is a collection you first have to find the required item and then overwrite it with the new object (moreover SingleOrDefault() will simply return null if condition is not satisfied).
You should write something like this (exact code depends on what MyObject is):
var item = Controller.MyObject.SingleOrDefault(x => x.Id == "user101");
if (item != null)
Controller.MyObject[Controller.MyObject.IndexOf(item)] = new OtherUser();
Please note that if you do not really need the check performed by SingleOrDefault() you can simplify the code (and avoid the double search performed in SingleOrDefault() and IndexOf()).
If this is "performance critical" maybe it is better to write an ad-hoc implementation that does this task in one single pass.
Try it in two lines:
var objectWithId = Controller.MyObject.SingleOrDefault(x => x.Id == "user101");
(objectWithId as WhateverTypeOfObjectOtherUserIs) = OtherUser();

TargetInvocationException thrown when attempting FirstOrDefault on IEnumerable

I suspect I'm missing something rather basic, yet I can't figure this one out.
I'm running a simple linq query -
var result = from UserLine u in context.Users
where u.PartitionKey == provider.Value && u.RowKey == id.Value
select u;
UserLine user = null;
try
{
user = result.FirstOrDefault();
}
For some reason this produces a TargetInvocationException with an inner exception of NullReferenceException.
This happens when the linq query produces no results, but I was under the impression that FirstOrDefault would return Default<T> rather than throw an exception?
I don't know if it matters, but the UserLine class inherits from Microsoft.WindowsAzure.StorageClient.TableServiceEntity
there are two possible reasons:
provider.Value
id.Value
Are you sure that theese nullables have value. You might want to check HasValue before
var result = from UserLine u in context.Users
where (provider.HasValue && u.PartitionKey == provider.Value)
&& (id.HasValue && u.RowKey == id.Value)
select u;
UserLine user = null;
try
{
user = result.FirstOrDefault();
}
I thought it produced a different error, but based on the situation in which the problem is occurring you might want to look to check if context.IgnoreResourceNotFoundException is set to false? If it is try setting it to true.
This property is a flag to indicate whether you want the storage library to throw and error when you use both PartitionKey and RowKey in a query and no result is found (it makes sense when you think about what the underlying REST API is doing, but it's a little confusing when you're using LINQ)
I figured it out - the problem occured when either id or provider had '/' in the value, which the id did. when I removed it the code ran fine
Understanding the Table Service Data Model has a section on 'Characters Disallowed in Key Fields' -
The following characters are not allowed in values for the
PartitionKey and RowKey properties:
The forward slash (/) character
The backslash () character
The number sign (#) character
The question mark (?) character
Here's some fun try putting the where query the other way around like this to see if it works (I heard a while ago it does!):
where (id.HasValue && u.RowKey == id.Value) && (provider.HasValue && u.PartitionKey == provider.Value)
Other than this you can now set IgnoreResourceNotFoundException = true in the TableServiceContext to receive null when an entity is not found instead of the error.
It's a crazy Azure storage thing.

Linq Where Clause Change based on Parameters

I have a linq statement that returns a list of records based on where clause
This where clause checks for two parameter values.
Out of which one parameter is optional.
so i need a suggestions if i can switch my where clause based on the optional Parameter
something like this
if(locid==0)
{
where (p.CustomerID == custid)
}
else{
where (p.CustomerID == custid) & (p.LocationID == locid )
}
can any one help me how can i get this work.
thanks
You could try writing it like this:
where (p.CustomerID == custid) && (locid == 0 || p.LocationID == locid )
Yes - queries can be composed (although you don't need this for this particular case as #rsbarro pointed out):
var query = p;
if(locid==0)
query = query.Where( p =>p.CustomerID == custid);
else
query = query.Where( p =>p.CustomerID == custid & p.LocationID == locid);
//any other conditions
As BrokenGlass mentioned, you should use composition:
IQueryable<Foo> query = unfiltered.Where(p => p.CustomerID == custId);
if (locid != 0)
{
query = query.Where(p => p.LocationID == locid);
}
Note that the query is not executed until you start reading data from it, so you needn't worry about this making multiple requests.
It looks like in your original post you were trying to use query syntax piecemeal - that won't work, but the "dot notation" is pretty simple here. You can always create your initial query using a query expression if you want - again, that query won't be executed immediately anyway.

How to convert a LINQ query from query syntax to query method

Linq and EF4.
I have this Linq query in query syntax I would like convert into query method.
Are you able to do it? I tried more tha 2 hours without success :-(
Thanks for your time
CmsContent myContentObj = (from cnt in context.CmsContents
from categoy in cnt.CmsCategories
where categoy.CategoryId == myCurrentCategoryId && cnt.ContentId == myCurrentContentId
select cnt).Single();
My original answer selected the wrong item. It's a bit more complicated than what I had (which Ani has posted). Here's what I believe is an equivalent query however and should perform better:
CmsContent myContentObj =
context.CmsContents
.Where(cnt => cnt.ContentId == myCurrentId
&& cnt.CmsCategories
.Any(categoy => categoy.CategoryId == myCurrentCategoryId))
.Single();
Here is a non-direct translation that I believe performs the same task in much less code:
var myContentObj = context.CmsContents.Single(
x => x.ContentId == myCurrentContentId &&
x.CmsCategories.Any(y => y.CategoryId == myCurrentCategoryId)
);
Here's how the C# compiler actually does it, with some help from .NET Reflector to verify:
var myContentObj = context
.CmsContents
.SelectMany(cnt => cnt.CmsCategories,
(cnt, categoy) => new { cnt, categoy })
.Where(a => a.categoy.CategoryId == myCurrentCategoryId
&& a.cnt.ContentId == myCurrentContentId)
.Select(a => a.cnt)
.Single();
Essentially, the 'nested' from clauses results in a SelectMany call with a transparent identifier (an anonymous-type instance holding the 'parent' cnt and the 'child' categoy). The Where filter is applied on the anonymous-type instance, and then we do another Select projection to get back the 'parent'. The Single call was always 'outside' the query expression of course, so it should be obvious how that fits in.
For more information, I suggest reading Jon Skeet's article How query expressions work.

LINQ Join needed?

Me again with a dumb question/scenario I need advice on.
I have the following that pulls back the contents of a column:
return getappropriateuserfield.tblAutoComplete
.Where(p => p.MemberId == memberid && p.ACItem == acitem)
.Select(p => p.ACColumn)
.Distinct()
.ToArray();
Depending upon this result, I'd like to then take the ACColumn result, go to tblPreferences, look down ColumnName, and if it matches an entry in there, pull back the Alias (present in tblPreferences)
So, for example we have tblAutoComplete:
MemberID ACItem ACColumn
1 2 UUF1
tblPreferences looks like
MemberID ColumnName Alias
1 UUF1 Category
If the user sticks in "2" as the ACItem, the first part result would be "UUF1" - the linq above does this.
How do I alter the linq so that the second part takes place, ie. takes the UUF1, looks in tblPreferences, checks out ColumnName, sees the result matches so the final result is the Alias, "Category"
Do I need to do this in 2 parts or can I do it as one query, potentially using a join?
Apologies for the thickness.
Looks like a join to me, which is probably most easily expressed with a query expression:
var query = from ac in foo.tblAutoComplete
where ac.MemberId == memberid && ac.ACItem == acitem
join pref in foo.tblPreferences.Where(x => x.MemberId == memberid)
on ac.ACColumn equals pref.ColumnName
select pref.Category;
Note that I've removed the Distinct() call here, which means you may get repeats. You can put Distinct() on the output, of course.
The result of will be an IQueryable<string> (assuming Category is a string). If you need more bits, you could use an anonymous type.
EDIT: I've edited the query so it's got an extra "where" clause when fetching the preferences to start with. That should be equivalent to adding MemberId to the join.

Resources