linq iteration need for single row? - linq

when i form the following code
Rabbit[] rbt=
new Rabbit[]
{
new Rabbit{ Name="Jobby", Vegetable=new Vegetable{ VegiName="carrot"}},
new Rabbit{ Name="hobby", Vegetable=new Vegetable{ VegiName="Beetroot"}}
};
var s = from bt in rbt where
bt.Vegetable.VegiName.CompareTo("carrot") == 0 select bt;
foreach (var v in s)
{
Console.WriteLine("{0}{1}",v.Vegetable.VegiName,v.Name);
}
my query returns single row only, then why do i need foreach iteration ? can't i use
Console.WriteLine("{0}{1}",s.Vegetable.VegiName,s.Name); directly ?

How is the compiler meant to know that your query will only return a single row?
Suppose you changed your data to include another carrot - or no carrot at all - what would you expect to happen.
If you should definitely get a single result, call Single to get it. If you may get multiple results, call First. If you may get multiple results or none, call FirstOrDefault. If you may get zero or one result, call SingleOrDefault. For example, for the first case:
var s = from bt in rbt where
bt.Vegetable.VegiName.CompareTo("carrot") == 0 select bt;
var veg = s.Single();
Console.WriteLine("{0}{1}",veg.Vegetable.VegiName,veg.Name);
Or alternatively:
var veg = rbt.Where(bt => bt.Vegetable.VegiName.CompareTo("carrot") == 0)
.Single();
Console.WriteLine("{0}{1}",veg.Vegetable.VegiName,veg.Name);

Because the type of the query IEnumerable<Rabbit>, not Rabbit. You can get what you want, though, by using a FirstOrDefault() or SingleOrDefault() at the end of your query.
var s = (from bt in rbt
where bt.Vegetable.VegiName.CompareTo("carrot") == 0
select bt)
.FirstOrDefault();

No, because LINQ does not know at compile time that s will return only a single row. Use the First() or Single() operator:
var v = (from bt in rbt where
bt.Vegetable.VegiName.CompareTo("carrot") == 0
select bt)
.First();

You can use the Single method to return a single value. Use SingleOrDefault if you suspect it may be null (ie. no results returned).
Rabbit result = s.SingleOrDefault();
if (result != null)
{
// use result
Console.WriteLine("{0} : {1}", result.Vegetable.VegiName, result.Name);
}
As others have mentioned, the alternative is to use First or FirstOrDefault to take the first result returned, if the query returns numerous results.

Related

Linq to SQL not querying memory

I am using Linq for SQL and have always thought that I was querying the results of a Query in memory. I have just looked at the database and it is showing many thousands of queries rather than 1 which is what I expected.
My approach has been to run a query and then use linq to search within the resultset.
IQueryable<mapping> fieldList = from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm;
for (int i=0;i<100;i++)
{
mapping thisVar = fieldList.FirstOrDefault(m => m.primaryItem == info.Name);
}
How can I stop Linq requerying everytime I access my resultset...
Thanks for your help!
When you write a LINQ query, the query doesn't get actually get executed until you perform an action that actually enumerates over it (deferred execution). Calling FirstOrDefault() is an example of one such method that enumerates over the result (the first result has to be found). You'll want to call a method or otherwise enumerate over the results once. That way when you want to refer to those results throughout your program, you do it on a stored copy.
The easiest way you can do that is to convert it to a list. That will put the results in memory as a list. You could then use that.
IQueryable<mapping> fieldList =
from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm;
// save it!
var result = fieldList.ToList(); // query is processed only once here
// do stuff with result
for (int i=0;i<100;i++)
{
// using the stored result
thisVar = result.FirstOrDefault(m => m.primaryItem == info.Name);
}
try this :
var fieldList = (from mm in db.mappings
join mi in db.metaItems on mm.secondaryMetaItemId equals mi.metaItemId
join mo in db.metaObjects on mi.metaObjectId equals mo.metaObjectId
where mm.linkageId == 277
select mm).AsEnumerable();
foreach (int i=0;i<100;i++)
{
mapping thisVar = fieldList.FirstOrDefault(m => m.primaryItem == info.Name);
}

How to request with random row linq

I am slow today
There is a request
"Take random child and put it into another garden."
I changed the code, but error in the last line of code "Does not contain a definition…and no extension method":
var query = db.Child.Where(x => x.Garden != null);
int count = query.Count();
int index = new Random().Next(count);
var ch = db.Child.OrderBy(x => query.Skip(index).FirstOrDefault());
ch.Garden_Id = "1";
What am I doing wrong?
It's hard to tell what you're doing wrong, because you didn't say why the results you're getting does not satisfy you.
But I can see two possible mistakes.
You're counting items with x.Garden != null condition, but taking from all children.
Take returns IEnumerable<T> even when you specify it to return only 1 item, you should probably use First instead.
I think your k should be
var k = db.Child.Where(x => x.Garden != null).Skip(rnd.Next(0,q)).First();

Truncating a collection using Linq query

I want to extract part of a collection to another collection.
I can easily do the same using a for loop, but my linq query is not working for the same.
I am a neophyte in Linq, so please help me correcting the query (if possible with explanation / beginners tutorial link)
Legacy way of doing :
Collection<string> testColl1 = new Collection<string> {"t1", "t2", "t3", "t4"};
Collection<string> testColl2 = new Collection<string>();
for (int i = 0; i < newLength; i++)
{
testColl2.Add(testColl1[i]);
}
Where testColl1 is the source & testColl2 is the desired truncated collection of count = newLength.
I have used the following linq queries, but none of them are working ...
var result = from t in testColl1 where t.Count() <= newLength select t;
var res = testColl1.Where(t => t.Count() <= newLength);
Use Enumerable.Take:
var testColl2 = testColl1.Take(newLength).ToList();
Note that there's a semantic difference between your for loop and the version using Take. The for loop will throw with IndexOutOfRangeException exception if there are less than newLength items in testColl1, whereas the Take version will silently ignore this fact and just return as many items up to newLength items.
The correct way is by using Take:
var result = testColl1.Take(newLength);
An equivalent way using Where is:
var result = testColl1.Where((i, item) => i < newLength);
These expressions will produce an IEnumerable, so you might also want to attach a .ToList() or .ToArray() at the end.
Both ways return one less item than your original implementation does because it is more natural (e.g. if newLength == 0 no items should be returned).
You could convert to for loop to something like this:
testColl1.Take(newLength)
Use Take:
var result = testColl1.Take(newLength);
This extension method returns the first N elements from the collection where N is the parameter you pass, in this case newLength.

Calling a function within a Linq query

If I want to iterate through a collection, and call a function on each element in the collection, I could go with :
foreach (var obj in objColl)
{
MyFunction(obj);
}
Should I want to do this with linq, I can use either of those :
//#1
var unused = (from var obj in objColl select MyFunction(obj)).ToList();
//#2
var unused = objColl.Select(obj => MyFunction(obj)).ToList();
I know this works, but it doesn't seem right. Of course, my actual cases are more complex queries that that, but it comes down to this since I could build my IQueryable with Linq and iterate through it and call the function.
Edit:
Here is one example of what I did. (Item# are things I can't disclose)
var dummyValue = (from
Item7 in dal.GetAgencyConvertions().Where(age => age.SourceName == "Item1" && age.TargetName == "Item2")
join Item6 in dal.GetAgencyConvertions().Where(age => age.SourceName == "Item2" && age.TargetName == "Item3") on Item6.TargetValue equals Item7.SourceValue
join agency in dal.GetAgencies() on Item7.SourceValue equals agency.Agency
orderby Item7.TargetValue
select vl.ValueListItems.Add(agency.ID, Item7.TargetValue)).ToList();
Go with the simple foreach, as you are clearly wanting to perform an action on (and/or using) the objects in your collection as opposed to wishing to project/filter/group/etc. the items in the sequence. LINQ is about the latter set of operations.
Edit: In the case of your update, I would simply create a query, and then iterate over the query in the foreach to perform the action.
var query = from Item7 in dal.GetAgencyConvertions().Where(age => age.SourceName == "Item1" && age.TargetName == "Item2")
join Item6 in dal.GetAgencyConvertions().Where(age => age.SourceName == "Item2" && age.TargetName == "Item3") on Item6.TargetValue equals Item7.SourceValue
join agency in dal.GetAgencies() on Item7.SourceValue equals agency.Agency
orderby Item7.TargetValue
select new { ID = agency.ID, Value = Item7.TargetValue };
foreach (var item in query)
vl.ValueListItems.Add(item.ID, item.Value);
To be frank, you have the same loop happening in your code, you merely mask it by using the ToList() extension method. As a byproduct, you are creating a list of values that you have no intention of using, while somewhat obfuscating the true intention of the code, all to save maybe a few characters.
Typically, a query shouldn't have any side effects (i.e. it shouldn't modify the state of the data or other data in your application) which raises the question, does MyFunction modify the state of your application? If it does, then you should use a foreach loop.
How about an Each() extension method?
public static void Each<T>(this IEnumerable<T> target, Action<T> action)
{
if (target == null) return;
foreach (T obj in target)
action(obj);
}

Difference between Where and Single

I'm trying to figure out the difference between Where(Expression) and Single(Expression).
Is the Expression passed into single forwarded to a Where function?
eg, are these two statements the same?
var result = context.Persons.Single(p => p.ID == 5);
var result2 = context.Persons.Where(p => p.ID == 5).Single();
Single returns you a Person, whereas the Where will return you an IEnumerable<Person>.
Passing the where expression into the single is just syntactic sugar.
Both the lines are functionally equivalent. The first I imagine could be ever so marginally more efficient. It's also easier on the eye in my opinion.
There is another difference though. Single() will throw an exception if the predicate used returns more than one element. In case the filter, when applied on an enumerable returns only one element, it returns that element without throwing an exception.
int[] a = {1, 2, 3};
var odd_Nos = a.Single(num => num % 2 != 0) // will throw exception (an InvalidOperationException)
var even_Nos = a.Single(num => num % 2 == 0) // will not throw exception
If you want just the first to appear, you can use the First() or FirstOrDefault() method.

Resources