Type error using Enumerable.Where - c#

I am working on a project to retrieve some data from a website. To complete the job, I decided to utilize the HtmlAgilityPack.
Everything is working fine except an issue I am facing related to lambda expressions. The error I am receiving is
Cannot implicitly convert type
'System.Collections.Generic.IEnumerable'
to 'bool'
var page = RetrievePage(url); //retrieve page
var document = GetDocument(page); //get the document
var optionNodes = document.Result.DocumentNode.SelectNodes("???"); //Select nodes based on selector
//remove empty lines
var filteredNodes = optionNodes[0].ChildNodes.Where(n => n.InnerText.Trim() != string.Empty);
using (var nodes = filteredNodes.GetEnumerator())
{
while (nodes.MoveNext())
{
//error
var children = nodes.Current.ChildNodes.Where(c => c.Attributes.Where(t => t.Value == "???"));
}
}
Appreciate your help.

The inner where will return rows. The outer where can only be an expression which has a boolean. So you have to change this:
var children = nodes.Current.ChildNodes
.Where(c => c.Attributes.Where(t => t.Value == "???"));
To this:
var children = nodes.Current.ChildNodes
.Where(c => c.Attributes.Any(t => t.Value == "???"));
Or this:
var children = nodes.Current.ChildNodes
.Where(c => c.Attributes.All(t => t.Value == "???"));
Or this:
var children = nodes.Current.ChildNodes
.Where(c => c.Attributes.Where(t => t.Value == "???").Count()>0);
Reference:
Enumerable.Any Method (IEnumerable, Func)
Enumerable.All Method

Related

How to avoid two embedded cycles in linq query C#

var listOfIds = new List<string>();
var allItems = IEnumerable<Info>();
foreach (var id in collectionIds)
{
listOfIds.AddRange(allItems
.Where(p => p.Data.FirstOrDefault(m => m.Key == "myId").Value == id)
.Select(x => x.Id));
}
I would like to avoid using AddRange but use only Add in this case and maybe use only FirstOrDefault in the place of where to avoid the last Select case.
Is this possible and if yes how?
Assuming your original code is giving you the correct data, specifically you are OK with:
Only concerned that the first item in p.Data contains a matching value and;
p.Data will always contains at least a single element.
Then this code will give you the same output:
var listOfIds = allItems
.Where(p => collectionIds.Contains(p.Data.First(m => m.Key == "myId").Value))
.ToList();
However, if you really do care that any value in p.Data matches, then this would be more appropriate:
var listOfIds = allItems
.Where(p => p.Data.Any(m => m.Key == "myId" &&
collectionIds.Contains(m.Value)))
.ToList();
How about this approach:
var listOfIds = new List<string>();
var allItems = IEnumerable<Info>();
var groupedAllItems = allItems.GroupBy(x => x.Data.FirstOrDefault(m => m.Key == "myId")?.Value ?? "MyIdNotFound");
//collectionIds should be of type HashSet<string> for the contains to be fast
listOfIds.AddRange(groupedAllItems.Where(x => collectionIds.Contains(x.Key)).SelectMany(x => x));

Simple LINQ Order by not working

I'm new with LINQ. I'm using this function:
public IEnumerable<Vendedores> GetVendedores()
{
using (var context = new OhmioEntities())
{
Vendedores _allvendors= new Vendedores();
_allvendors.Nombre = "All Vendors";
_allvendors.ID_Vendedor = -1;
var query = context.Vendedores;
var _vendors= query.Where(f => f.Activo == true).OrderBy(o=>Nombre).ToList();
_vendors.Insert(0, _allvendors);
return _vendors;
}
}
It should give me order list of active vendors. The where part work fine, but the order is ignored and the records after the .ToList are in the original table order. What i'm i doing wrong?
Thank you!
I think you need o.Nombre instead of Nombre
var _vendors = query
.Where(f => f.Activo)
.OrderBy(o=> o.Nombre)
.ToList();
Also f => f.Activo == true can be written as f => f.Activo.
it should be this way:
var _vendors= query.Where(f => f.Activo == true).OrderBy(o=>o.Nombre).ToList();

Linq - Conversion error when simulating an exists expression

Im having a problem with Linq using Lambda Expressions. Im trying to do this select
SELECT L.IDLLAMADO FROM LLAMADOS L WHERE EXISTS (SELECT D.IDLLAMADO FROM DIAGNOSTICO D WHERE D.DESCRIPCION LIKE '%SOME VALUE%')
Some notes:
Im using IQueryable because Im appending joins and where depending on
the parameters of the method.
In the example I mapped only a property in my complex class because the rest are not useful in the example.
diagonostico is a string parameter.
My code is:
DbSet<Llamados> llamados = context.Set<Llamados>();
IQueryable<ComplexLlamadosAfil> query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);
There is not compilation error but when i run this i keep getting this error:
The object type
'System.Data.Objects.ObjectQuery`1[GAMP.MO.VW_DIAGNOSTICOS_LLAMADO]'
cannot be converted into
'System.Data.Entity.DbSet`1[GAMP.MO.VW_DIAGNOSTICOS_LLAMADO]'.
I also tried using .TakeWhile() instead of .Where() but no success.
Thanks for reading guys,
Pablo.
well, the message is rather clear, no ?
I would do
//Don't tell that it's a DbSet<Llamados>. You want an IQueryable<Llamados>
IQueryable<Llamados> llamados = context.Set<Llamados>().AsQueryable();
IQueryable<ComplexLlamadosAfil> query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);
or just use var
var llamados = context.Set<Llamados>().AsQueryable();
var query = llamados
.Select(e => new ComplexLlamadosAfil { IdLlamado = e.IdLlamado });
//If some conditions
query = query.Where(e => diagnosticos.Any(d => d.IdLlamado == e.IdLlamado &&
d.Descripcion.Contains(diagnostico)) == true);

Cannot convert IQueryable<IEnumerable<string>> to return type IEnumerable<string>

In the following function I get an error when I try to return a value saying:
Cannot convert
System.Linq.IQueryable<System.Collections.Generic.IEnumerable<string>>
to return type System.Collections.Generic.IEnumerable<string>
public IEnumerable<string> GetModuleKindPropertyNames(long moduleKindId)
{
var configurationId = GetModuleKindPertypeConfigurationId(moduleKindId);
var propertyNames = _dbSis.ModuleKinds
.Where(t => t.PerTypeConfigurationId == configurationId)
.Select(x => x.PerTypeConfiguration.Properties
.Select(z => z.Name));
return propertyNames; //red line below property names
}
How can I solve this issue?
It looks like you want to select items from a collection within a collection and flatten the result into a single sequence.
Conceptually, something like:
If that's the case, you're looking for the SelectMany method:
var propertyNames = _dbSis.ModuleKinds
.Where(t => t.PerTypeConfigurationId == configurationId)
.SelectMany(x => x.PerTypeConfiguration.Properties)
.Select(z => z.Name);

Lambda expression: Where clause for Include list

So I got something like this:
var myObj = db.SomeObject
.Include("Tasks")
.SingleOrDefault(x => x.Id == someObjectId);
if (myObj != null)
{
myObj.Tasks = myObj.Tasks.OrderBy(x => x.Number).ToList();
}
Here I want to be able to put a condition (where) on my Include, for instance:
.where task.IsDeleted == false
Thusfar I have not found a solution.
I am aware of the fact that I could use the where together with where I order the tasks but this however, does not run on the database but in stead uses memory. I want it to run on the database.
Does anyone here know how I can do this?
If so, is there also a way to put the order by condition to the included list of tasks?
Something like this, returs you your original object with its child collection filtered and sorted.
SomeObject a = db.SomeObjects.Where(x => x.Id == someobjectid)
.Select(
x =>
new
{
someObject = x,
task = x.Tasks.Where(task => task.IsDeleted == false)
.OrderBy(task => whatever)
})
.Select(x => x.someObject).Single();
It's actually loosing the collection of activities in the last select so you can do this :
SomeObject a = db.SomeObjects.Where(x => x.Id == someobjectid)
.Select(
x =>
new
{
someObject = x,
task = x.Tasks.Where(task => task.IsDeleted == false)
.OrderBy(task => whatever)
});
return a.FirstOrDefault().someObject;
To do this is EF, you need to specify a projection with a Select clause.
Something like this will get just the data you want from the db:
var anonymous = db.SomeObject.Where( x => x.Id == someObjectId )
.Select( x => new
{
SomeObject = x,
Tasks = x.Tasks
.Where( o => !o.IsDeleted )
.OrderBy( o => ... )
}
)
.SingleOrDefault()
;
You will end up with an instance of the anonymous type , but you can easily fix that up on the client:
MyObject myObject = anonymous.SomeObject;
myObject.Tasks = anonymous.Tasks;
The simple answer is: You can't do that.
Why? Because you query SomeObject.
Each returned SomeObject contains all referenced data, because if it wouldn't it wouldn't represent the actual object in the database.
What about getting them separately:
var myObj = db.SomeObject
.SingleOrDefault(x => x.Id == someObjectId);
var tasks = db.SomeObject
.Where(x => x.Id == someObjectId)
.SelectMany(x => x.Tasks)
.Where(x => !x.Deleted);

Categories