So I know the query notation
var word = from s in stringList
where s.Length == 3
select s;
is equivalent to the dot notation
var word = stringList
.Where(s => s.Length == 3)
.Select(s => s);
But how do you convert this dot notation to a query notation?
var word = wordsList
.Single(p => p.Id == savedId);
I couldn't find much resources on Google.
You can't. A lot of LINQ functions can't be used in the query syntax. At best, you can combine both and do something like
var word = (from p in wordsList
where p.Id == savedId
select p).Single()
but in the simple case of collection.Single(condition), the "dot notation" seems more readable to me.
There is a list of keywords used by LINQ on MSDN, you can see which functions are integrated into the language from that list.
Single doesn't have an exact equivalent in query notation.
The best you can do is to wrap your query in parentheses and call .Single yourself.
The only thing you can do is:
var word = (from w in wordsList
where w.Id == savedId
select w).Single();
but It will not be exactly the same. It will be transformed into
var word = wordsList
.Where(p => p.Id == savedId)
.Single();
Single is not part of the query notation. You could change your first example to the following to achieve what you want:
var word = (from s in stringList where s.Length == 3 select s).Single();
Related
Need your help: I have Datable that has datarows like :
test1
test1:1
test1:1:1
test1:2
I need to select only rows that contain ":" only once.
Result should be like :
test1:1
test1:2
Any ideas how to make it ??
I stuck after :
var result = dTable.AsEnumerable().Where(dr => dr.Field<string>("Name").Contains(":"));
,where "Name" is a column Name.
Thank you in advance
var result = dTable.AsEnumerable()
.Where(dr => dr.Field<string>("Name").Count(z=>z==':')==1);
or
var result = dTable.AsEnumerable()
.Where(dr => dr.Field<string>("Name").Where(z=>z==':').Count()==1);
or
var result = dTable.AsEnumerable()
.Where(dr => dr.Field<string>("Name").IndexOf(':') == dr.Field<string>("Name").LastIndexOf(':') && dr.Field<string>("Name").Contains(":"));
You can convert the content of the Field to a Char array and then count the number of times you get the ':'
var result = dt.AsEnumerable()
.Where(dr => dr.Field<string>("Name")
.ToCharArray()
.Count(c => c == ':') == 1);
Try this instead:
var result = dTable.AsEnumerable().Where(dr => dr.Field<string>("Name").Count(f => f == ':') == 1);
With LINQ, this is very easy using x.Count().
If you want to do it without LINQ, try this:
var result = dTable.AsEnumerable().Where(dr => dr.Field<string>("Name").Split(':').Length - 1 == 1);
See the top answer at this other Stack Overflow question, which has something similar. I don't usually use LINQ, so forgive me if my code doesn't work. Hope this helps!
I've set up a search textbox where the search will grab every word individually and search through a field using Contains.
Is there a way to search an array of string through Contains?
//Keep in mind that the array would be generated dynamically through textbox
string[] searchWords = { "hello", "world", "today" };
var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => a.Title.Contains(searchWords));
searchWords obiviously does not work but trying to show what I want to achieve. searchWords[0] works because it is just one word.
I also tried below as suggested in other links but now the WHERE clause does not show up in query when i run debugger or profiler:
`var articles = _swmDbContext.Articles
.Include(c => c.Category)
.Where(a => searchWords.Any(w => a.Title.Contains(w)));
`
It seems like Entity Framework Core does not translate .Any and .All with .Contains in the above query to SQL statements. Instead it loads all otherwise matching data and does the search in memory.
If you want to find Articles which contain all search words in the Title you could dynamically add .Where conditions (I had a test database with Persons and a Comment field):
var query = (IQueryable<Person>)dbContext.Persons
.Include(p => p.TaxIdentificationNumber);
foreach (var searchWord in searchWords)
{
query = query.Where(p => p.Comment.Contains(searchWord));
}
var persons = query.ToList();
But if you want to find articles which contain any of the search words then you would need an OR in the .Where clause.
Written manually it would look like this:
.Where(p => p.Comment.Contains(searchWords[0]) || p.Comment.Contains(searchWords[1]))
But you can build the expression dynamically:
Expression<Func<Person, bool>> e1 = p => p.Comment.Contains(searchWords[0]);
Expression<Func<Person, bool>> e2 = p => p.Comment.Contains(searchWords[1]);
Expression<Func<Person, bool>> e3 = p => p.Comment.Contains(searchWords[2]);
var orExpression1 = Expression.OrElse(e1.Body, Expression.Invoke(e2, e1.Parameters[0]));
var orExpression2 = Expression.OrElse(orExpression1, Expression.Invoke(e3, e1.Parameters[0]));
var finalExpression = Expression.Lambda<Func<Person, bool>>(orExpression2, e1.Parameters);
and use it like this:
var persons = dbContext.Persons.Where(finalExpression).ToList();
as a function:
Expression<Func<Person, bool>> BuildOrSearchExpression(string[] searchWords)
{
// searchWords must not be null or empty
var expressions = searchWords.Select(s => (Expression<Func<Person, bool>>)(p => p.Comment.Contains(s))).ToList();
if (expressions.Count == 1) return expressions[0];
var orExpression = expressions.Skip(2).Aggregate(
Expression.OrElse(expressions[0].Body, Expression.Invoke(expressions[1], expressions[0].Parameters[0])),
(x, y) => Expression.OrElse(x, Expression.Invoke(y, expressions[0].Parameters[0])));
return Expression.Lambda<Func<Person, bool>>(orExpression, expressions[0].Parameters);
}
and use it
var persons = dbContext.Persons
.Include(p => p.TaxIdentificationNumber)
.Where(BuildOrSearchExpression(searchWords))
.ToList();
If you exchange the .OrElse with .AndAlso all search words must be found like with multiple .where clauses.
When I did some research I also stumbled upon the PredicatedBuilder http://www.albahari.com/nutshell/predicatebuilder.aspx and this SearchExtension https://stackoverflow.com/a/31682364/5550687. But I have not tried them and I don't know if they work with EF Core.
I am using the HTMLAgilityPack to parse through some html. I am getting the result set that I am expecting when using and xpath query combined with a linq query. Is there a way that I could combine them both into a single LINQ query?
var test = doc.DocumentNode.SelectNodes("//div[#class='product']");
foreach (var item in test)
{
var result = from input in item.Descendants("span")
where input.Attributes["class"].Value == "Bold"
where input.InnerHtml.ToUpper() == "GetItem"
select input;
return result;
}
If you'd want to gather all the spans together (if I'm correct in assuming that's what you want)...
I'd first convert it to a more fluent notation (I find SelectMany much easier to grasp that way - but that's just me)
(disclaimer: I'm writing this from memory, copy/pasting your code - not by VS at the moment - you'd need to check, make it write if any issues - but I think I got it ok more or less)
var test = doc.DocumentNode.SelectNodes("//div[#class='product']");
foreach(var item in test)
item.Descendants("span").Where(input => input.Attributes["class"].Value == "Bold").Where(input => input.InnerHtml.ToUpper() == "GetItem").Select(input => input);
and finally...
var allSpans = doc.DocumentNode.SelectNodes("//div[#class='product']")
.SelectMany(item => item.Descendants("span").Where(input => input.Attributes["class"].Value == "Bold").Where(input => input.InnerHtml.ToUpper() == "GetItem"));
...or along those lines
Just wanted to show you the other way to do SelectMany in Linq. This is a style choice, and many people here in SO would prefer the .SelectMany extension method, because they can see how the Monad is applied to the IEnumerable. I prefer this method since its much closer to how a functional programming model would do it.
return from product in doc.DocumentNode.SelectNodes("//div[#class='product']")
from input in product.Descendants("span")
where input.Attributes["class"].Value == "Bold"
where input.InnerHtml.ToUpper() == "GetItem"
select input;
return (
from result in
from item in doc.DocumentNode.SelectNodes("//div[#class='product']")
from input in item.Descendants("span")
where input.Attributes["class"].Value == "Bold"
where input.InnerHtml.ToUpper() == "GetItem"
select input
select result
).First();
If you really wanted it all in one query you could with something like this:
var result = doc.DocumentNode.SelectNodes("//div[#class='product']")
.SelectMany(e => e.Descendants("span")
.Where(x => x.Attributes["class"].Value == "Bold" &&
x.InnerHtml.ToUpper() == "GetItem"))
.ToList();
return result;
I would recommend spacing it out a bit though for the sake of readability, something more like this:
var result = new List<SomeType>();
var nodes = doc.DocumentNode.SelectNodes("//div[#class='product']");
nodes.SelectMany(e => e.Descendants("span")
.Where(x => x.Attributes["class"].Value == "Bold" &&
x.InnerHtml.ToUpper() == "GetItem"));
return result.ToList();
The SelectMany() method will flatten the results of the inner queries into a single IEnumerable<T>.
I have this code :
foreach (Package pack in Packages)
{
filteredResults = filteredResults.Where(o => o.ID == pack.ID);
}
the only problems is that I filter the result N time (so N where).
What I'd like to do is to filter the result only one time (only a where clause) with N expression. Somethings like :
Where o.ID == pack.ID OR o.ID == pack.ID OR o.ID == pack.ID OR o.ID == pack.ID...
Is it possible to do this with LINQ?
Something like the code below should work, or at least steer you in the right direction.
-- Get all the package IDs you want to select on.
var packIDs = from pack in Packages
select pack.ID;
-- Return all results where the ID is in the package ids above.
filteredResults = from result in filteredResults
where packIDs.Contains(result.ID)
select result;
The above assumes your and's were a logic mistake and you meant ors.
var packIds = Packages.Select(x=>x.ID).ToArray();
filteredResults = filteredResults.Where(o=> packIds.Contains(o.ID));
If this is linq to sql this will get translated into:
WHERE ID IN (1,2,3,4)
Something like this might help you:
filteredResults = originalResults.Where(o => Packages.Any(p => p.ID == o.ID));
Do you not want Intersect()? i.e
var ids = filteredResults.Select( fr => fr.Id ).Intersect(Packages.Select( p => p.PackID ) ) ;
I think you need to use expression with LinqKit
var v = from utente in db.Utente
select utente;
Expression<Func<Utente, bool>> expr = c => c.Age == 26;
expr = expr.Or<Utente>(c => c.Name != "Matteo");
v = v.Where(expr.Expand());
The result is:
SELECT...... FROM......
WHERE (26 = [Extent1].[Age ]) OR ('Matteo' <> [Extent1].[Name])
I have the same issue, i try this solution
I was wondering if there is a way to get a list of results into a list with linq to xml. If I would have the following xml for example:
<?xml version="1.0"?>
<Sports xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SportPages>
<SportPage type="test">
<LinkPage>
<IDList>
<string>1</string>
<string>2</string>
</IDList>
</LinkPage>
</SportPage>
</SportPages>
</Sports>
How could I get a list of strings from the IDList?
I'm fairly new to linq to xml so I just tried some stuff out, I'm currently at this point:
var IDs = from sportpage in xDoc.Descendants("SportPages").Descendants("SportPage")
where sportpage.Attribute("type").Value == "Karate"
select new
{
ID = sportpage.Element("LinkPage").Element("IDList").Elements("string")
};
But the var is to chaotic to read decently. Isn't there a way I could just get a list of strings from this?
Thanks
This query works - tested and verified:
var ID2 = (from sportpage in xDoc.Descendants("SportPages").Descendants("SportPage")
where sportpage.Attribute("type").Value == "Karate"
select sportpage)
.Descendants("LinkPage")
.Descendants("IDList")
.Elements("string")
.Select(d => d.Value)
.ToList();
Gives me a list of two strings, "1" and "2".
var myStrings = xDoc.Descendants("SportPage")
.Where(d => d.Attribute("type").Value == "Karate")
.Descendants("IDList")
.Descendants("string")
.Select(d => d.Value);
to see your string:
xDoc.Descendants("SportPage")
.Descendants("IDList")
.Where(d => d.Attribute("type").Value == "Karate")
.Descendants("string")
.Select(d => d.Value)
.ToList()
.ForEach(Console.WriteLine);
Do you mean this?
List<string> IDs = xDoc.Descendants("SportPages").Descendants("SportPage")
.Where( anySportPage => anySportpage.Attribute("type").Value == "Karate" )
.Select( karateSportPage => karateSportpage.Element("LinkPage").Element("IDList").Elements("string"))
.ToList();
I think the reason you find the "var" chaotic is your creation of the anonymous type with the "new" in your select. If you just select the one item you're after then the var will not be an anonymous type.
e.g.
select sportpage.Element("LinkPage").Element("IDList").Elements("string");
However, my preference would be to do that using the . notation like this.
List<string> ids = xDoc.Elements("SportPages").Elements("SportPage").Where(sportPage => sportPage.Attribute("type").Value == "Karate").Elements("LinkPage").Elements("IDList").Elements("string").Select(id => id.Value).ToList();
The biggest issue you were having was that you didn't grab the .Value from the returned element set. But here's another way to do it.
var ids = from sportPage in xDoc.Descendants("SportPage")
let attrib = sportPage.Attribute("type")
where attrib != null
let type = attrib.Value
where !string.IsNullOrEmpty(type)
&& type == "Karate"
from id in sportPage.Descendants("IDList").Elements()
select id.Value;