简体   繁体   中英

Querying Child Collections 2 levels deep in LINQ

i currently have a linq to entities model set up as follows

each Sample has a collection Of Tests each Test has a collection of Results Each Result has Status property valuing whether it is Available or Completed

how would i write a linq query that would: get the samples that have available Results retaining only the tests that have available results and only the results in each test that are available

having trouble getting my head around this problem and help with getting this written would really help alot

Classes:

public class Sample
{
    public Sample()
    {
        Tests = new List<Test>();
    }

    public          int                     Id              { get; set; }
    public          string                  IdText          { get; set; }
    public          DateTime                SampleDate      { get; set; }
    public          DateTime                LoginDate       { get; set; }
    public          string                  Container       { get; set; }
    public          string                  Product         { get; set; }
    public          string                  Name            { get; set; }
    public          string                  Status          { get; set; }

    public virtual  SamplePoint SamplingPoint { get; set; }
    public virtual  SampleTemplate SampleTemplate { get; set; }
    public virtual  Customer ForCustomer { get; set; }
    public virtual  ICollection<Test> Tests { get; set; }

public class Test
{

    public Test()
    {
        Results = new List<Result>();
    }

    public string Id { get; set; }
    public string Status { get; set; }
    public string Analysis { get; set; }
    public string ComponentList { get; set; }
    public virtual Instrument InstrumentUsed { get; set; }
    public virtual ICollection<Result> Results { get; set; }
    public virtual Sample ForSample { get; set; }
}

public class Result
{
    public string Id { get; set; }
    public string TestNumber { get; set; }
    public string Status { get; set; }
    public string Analysis { get; set; }
    public string ComponentName { get; set; }
    public string Text { get; set; }
    public string Units { get; set; }
    public double Value { get; set; }
    public int OutOfRange { get; set; }
    public DateTime SampledDate { get; set; }
    public DateTime SampleLoginDate { get; set; }
    public string SamplePoint { get; set; }
    public virtual Sample ForSample { get; set; }
    public virtual Test ForTest { get; set; }
}

If I understand your table structure then it's fairly easy to query down to get the results that you're interested in.

I put together a simple set of classes to test the results.

public static class db
{
    public static List<Sample> Samples = new List<Sample>();
}

public class Sample
{
    public string Name;
    public List<Test> Tests = new List<Test>();
}

public class Test
{
    public string Name;
    public List<Result> Results = new List<Result>();
}

public class Result
{
    public string Name;
    public string Status;   
}

And I created this set of test data:

测试数据

From here it is easy to query the data down to just available results:

var query =
    from s in db.Samples
    from t in s.Tests
    from r in t.Results
    where r.Status == "Available"
    select new { Sample = s.Name, Test = t.Name, Result = r };

Which gives me this data:

不良数据

But that doesn't group the data by Sample and Test properly.

One way to do it properly is to create new Sample & Test objects that contain only the available results, like so:

var query =
    from s in db.Samples
    from rt in (
        from t in s.Tests
        from r in t.Results
        where r.Status == "Available"
        group r by t into rts
        select new Test()
        {
            Name = rts.Key.Name,
            Results = rts.ToList()
        })
    group rt by s into srts
    select new Sample()
    {
        Name = srts.Key.Name,
        Tests = srts.ToList()
    };

This produces this result:

新数据

However, it might not be possible, or desirable, to create new instance of objects that look like actual entities but are not actually from the database. It might be possible to accidentally persist one of these objects back to the database and wipe out correct records!

So, an alternative, which I think is the best, is to create a nested structure that contains the unmodified database entities and includes the available tests in an extra properly all while keeping the nested structure!!

Here's how:

var query =
    from s in db.Samples
    from rt in
        (from t in s.Tests
        from r in t.Results
        where r.Status == "Available"
        group r by t into rts
        select new
        {
            Test = rts.Key,
            AvailableResults = rts.ToArray()
        })
    group rt by s into srts
    select new
    {
        Sample = srts.Key,
        AvailableTests = srts.ToArray()
    };

And this produces:

好数据

With these results you still have access to the unchanged Sample and Test objects, but all filtered by the available results.

Let me know if this helps.

Without seeing your actual class structure, I'm hoping this can help in some way:

var testsWithAvailableResults = from test in dbContext.Tests
                                    select new {
                                        Results = (from result in test.Results where result.Status == "Available")
                                     };

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM