How to request with random row linq - 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();

Related

Linq :varName.hits.select (x=>x.document).toList()

I have the below codes :
var predicate = PredicateBuilder.True().And(p => p["_latestversion"] == "1");
predicate = predicate.And(GetDefaultTemplatePredicatesExpression());
if(!string.IsNullOrEmpty(path))
predicate = predicate.And(GetPathPredicateExpression(path));
var results = context.GetQueryable().Where(predicate).OrderByDescending(p=> p.Views).GetResults();
if (results != null)
{
if (results.Hits.Any())
{
return results.Hits.Select(x => x.Document).ToList();
}
}
I am retrieving a list of records based on the latest version. But this code does not indicate the number of records to return back. Can I check whether does the above codes return whatever number of records that it retrieve from the database?
It's unclear to me what that GetResults() call would be returning (is that an extension method you've defined? I can't find anything relevant as part of the .NET framework.), which makes it hard to make a firm statement about anything else.
I believe you can split the line:
var results = context.GetQueryable<ArticleItem>()
.Where(predicate)
.OrderByDescending(p=> p.Views)
.GetResults();
into three lines:
var query = context.GetQueryable<ArticleItem>()
.Where(predicate)
.OrderByDescending(p=> p.Views);
var count = query.Count();
var results = query.GetResults();
Which I think will give you would you want.

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.

LINQ query returning null results

I have the following code
nodes = data.Descendants(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Results")).Nodes();
System.Collections.Generic.IEnumerable<Result> res = new List<Result>();
if (nodes.Count() > 0)
{
var results = from uris in nodes
select new Result
{
URL =
((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Url")).Value,
Title =
((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Title")).Value,
Description =
((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Description")).Value,
DateTime =
((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}DateTime")).Value,
};
res = results;
}
Where Results is a object who has those URL, Title, Description, and DateTime variables defined.
This all works fine normally, but when a 'node' in nodes doesnt contain a Description element (or at least I think thats whats throwing it) the program hits the "res = results;"
line of code and throws a 'object reference not set to...' error and highlights the whole section right after "select new Results"..
How do I fix this?
The simplest way is to cast to string instead of using the Value property. That way you'll end up with a null reference for the Description instead.
However, your code can also be made a lot nicer:
XNamespace ns = "http://schemas.microsoft.com/LiveSearch/2008/04/XML/web";
var results = data.Descendants(ns + "Results")
.Elements()
.Select(x => new Result
{
URL = (string) x.Element(ns + "Url"),
Title = (string) x.Element(ns + "Title"),
Description = (string) x.Element(ns + "Description"),
DateTime = (string) x.Element(ns + "DateTime")
})
.ToList();
See how much simpler that is? Techiques used:
Calling ToList() on an empty sequence gives you a list anyway
This way you'll only ever perform the query once; before you were calling Count() which would potentially have iterated over each node. In general, use Any() instead of Count() > 0) - but this time just making the list unconditional is simpler.
Use the Elements() method to get child elements, rather than casting multiple times. (Your previous code would have thrown an exception if it had encountered any non-element nodes)
Use the implicit conversion from string to XNamespace
Use the +(XNamespace, string) operator to get an XName
If the Description element is not included you should test if this
((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Description"))
is not null before using Value. Try this code:
var results = from uris in nodes let des = ((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Description"))
select new Result
{
URL = ((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Url")).Value,
Title = ((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}Title")).Value,
Description = (des != null) ? des.Value : string.Empty,
DateTime = ((XElement)uris).Element(XName.Get("{http://schemas.microsoft.com/LiveSearch/2008/04/XML/web}DateTime")).Value,
};

LINQ: Field is not a reference field

I've got a list of IQueryable. I'm trying to split this list into an array of IQueryable matching on a certain field (say fieldnum) in the first list...
for example, if fieldnum == 1, it should go into array[1]. I'm using Where() to filter based on this field, it looks something like this:
var allItems = FillListofMyObjects();
var Filtered = new List<IQueryable<myObject>(MAX+1);
for (var i = 1; i <= MAX; i++)
{
var sublist = allItems.Where(e => e.fieldnum == i);
if (sublist.Count() == 0) continue;
Filtered[i] = sublist;
}
however, I'm getting the error Field "t1.fieldnum" is not a reference field on the if line. stepping through the debugger shows the error actually occurs on the line before (the Where() method) but either way, I don't know what I'm doing wrong.
I'm farily new to LINQ so if I'm doing this all wrong please let me know, thanks!
Why don't you just use ToLookup?
var allItemsPerFieldNum = allItems.ToLookup(e => e.fieldnum);
Do you need to reevaluate the expression every time you get the values?
Why not use a dictionary?
var dictionary = allItems.ToDictionar(y => y.fieldnum);

linq iteration need for single row?

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.

Resources