I am trying to write a fairly complex query. Here is what I have:
public class ClassA
{
public ICollection<ClassB> classBObjects { get; set; }
}
public class ClassB
{
public string Name { get; set; }
public string Value { get; set; }
public bool IsVisible { get; set; }
}
While getting the list of ClassA objects, I need to check the collection property (classB objects) against IEnumerable params and only get those ClassA objects along with the list of ClassB objects that have a match.
So if I have :
var objectAs = new[]
{
new ClassA
{
classBObjects = new[]
{
new ClassB { Name = "X", Value = "1", IsVisible = true },
new ClassB { Name = "Y", Value = "2", IsVisible = true },
new ClassB { Name = "Z", Value = "3", IsVisible = true },
},
},
new ClassA
{
classBObjects = new[]
{
new ClassB { Name = "W", Value = "4", IsVisible = true },
new ClassB { Name = "X", Value = "1", IsVisible = true },
},
},
};
var parameters = new[]
{
new { name = "X", value = "1", },
new { name = "Y", value = "2" },
};
I should get back:
objectA1
objectB1
objectB2
I am wondering if IntersectBy may help me achieve the result I am looking for but not quite sure how to form the query.
Also, I believe this will have to be in-memory computation:
var objectAList = context.ClassA.AsEnumerable();
so probably not so performant?
EDIT: Thanks for the answers and apologies for the vagueness of my previous description. I will try and rectify it. What I need is a list of ClassA objects which has a matching ClassB for ALL parameters. So, for the above example, the result should actually be:
objectA1
objectB1
objectB2
The following (based off of one of the posted answers) would work if the requirement was to get a list with at least a parameter match but I need all parameters to match so trying to come up with a query that will work.
var result= classAObjects.SelectMany(a => a.classBObjects.Where(b =>
parameters.Any(p => p.Name == b.Name && p.Value == b.Value)
)), (classAObject, classBObject) => new { classAObject }).ToList();
Also, someone had asked about the involvement of Entity Framework. So basically, I get the data from the database. However, I don't think it is possible to write a LINQ-to-Entities query that involves my parameters list so I first fetch classAObjects collection from database and then perform the query on it.
Given below is the solution I came up with:
var results = classAObjects
.Select(a =>
new
{
a,
match = parameters.All(p => a.classBOjects.Any(
b => b.Name == p.Name && b.Value == p.Value
))
}
).Where(r => r.match.Equals(true)).Select(r => r.a)
.ToList();
Update: jdweng's solution helped me figure out the solution so I am going to go ahead and mark that as the answer.
Try following :
class Program
{
static void Main(string[] args)
{
List<ClassA> objects = new List<ClassA> {
new ClassA() { classBObjects = new List<ClassB>() {
new ClassB() { Name = "X", Value = "1", IsVisible = true},
new ClassB() { Name = "Y", Value = "2", IsVisible = true},
new ClassB() { Name = "Z", Value = "3", IsVisible = true}
} },
new ClassA() { classBObjects = new List<ClassB> {
new ClassB { Name = "W", Value = "4", IsVisible = true},
new ClassB { Name = "X", Value = "1", IsVisible = true}
} }
};
List<Parameters> parameters = new List<Parameters>() { new Parameters() { Name = "X", Value = "1" }, new Parameters() { Name = "Y", Value = "2" } };
var results = objects.SelectMany(x => x.classBObjects.Where(y => parameters.Any(z => y.Name == z.Name && y.Value == z.Value))).ToList();
}
}
class ClassA {
public ICollection<ClassB> classBObjects { get; set; }
}
class ClassB {
public string Name { get; set; }
public string Value { get; set; }
public bool IsVisible { get; set; }
}
class Parameters
{
public string Name { get; set; }
public string Value { get; set; }
}