Reputation: 125
I'm trying to create a linq query that can be able to search through an array of objects. This is what I can do on the SQL
select * from Compliance c
join ComplianceDetail cd on cd.ComplianceID = c.ComplianceID
join ComplianceDetailAnswer cda on cd.ComplianceDetailID = cda.ComplianceDetailID
where cda.ComplianceQuestionValue like '%test%'
As you can see, the heirarchy is one Compliance
to many ComplianceDetail
and one ComplianceDetail
to many ComplianceDetailAnswer
. I want to search on the ComplianceDetailAnswer
table but I have no idea how to do it in linq.
Here's my original code but I'm searching on the Compliance
table itself
compliances = await _contextProvider.Context.Compliances
.Where(c.IncidentReportID.ToString().Contains(searchText) || searchText == null)
.ToListAsync();
This is just searching on the Compliance
table, but I want to be able to search on its child table ComplianceDetailAnswer
Upvotes: 0
Views: 170
Reputation: 1741
Here's another answer using System.Linq
. Each IEnumerable<T>
supports Take()
and Skip()
.
As long as you do not iterate the result - in my case compliancesWithQuestionsLikeTest
the query will not be executed, since it's just an IQueryable
object.
Adding Take()
and Skip()
should therefore generate an SQL statement that has something like TAKE FIRST 50 ROWS ONLY
and thus give you a performance benefit.
class Compliance
{
public List<ComplianceDetail> ComplianceDetails { get; set; }
}
class ComplianceDetail
{
public List<ComplianceDetailAnswer> ComplianceDetailAnswers { get; set; }
}
class ComplianceDetailAnswer
{
public string Question { get; set; }
}
static void Main(string[] args)
{
var obj = new Compliance();
var queryList = new List<Compliance> { obj };
var compliancesWithQuestionsLikeTest = queryList.Where(compliance => compliance.ComplianceDetails
.Any(complianceDetail => complianceDetail.ComplianceDetailAnswers
.Any(answer => answer.Question.Contains("test"))));
}
In this sample queryList
basically is your _contextProvider.Context.Compliances
.
EDIT:
Please note that this query will return the Compliance
objects in an unmodified manner. You will get only Compliance
s containing a question with test
. The Compliance
objects however also contain all other question related to them in the database. The objects are not manipulated!
As you can see in Tomas Chabada's answer he creates new objects only containing questions with "test" in select new { c, cd, cda }
.
Upvotes: 1
Reputation: 3019
You can compose it in LINQ easily. Here is an example using query syntax:
var result = from c in Compliance
join cd in ComplianceDetail on c.ComplianceID equals cd.ComplianceID
join cda in ComplianceDetailAnswer on cd.ComplianceDetailID equals cda.ComplianceDetailID
where cda.ComplianceQuestionValue.Contains("test")
select new { c, cd, cda };
If you need to call Skip
and Take
simply wrap your expression to parentheses and the you can chain other LINQ methods
var result = (from c in Compliance
join cd in ComplianceDetail on c.ComplianceID equals cd.ComplianceID
join cda in ComplianceDetailAnswer on cd.ComplianceDetailID equals cda.ComplianceDetailID
where cda.ComplianceQuestionValue.Contains("test")
select new { c, cd, cda }).Skip(1).Take(100);
Upvotes: 1