简体   繁体   中英

Subquery in select Linq

My query is as below

var result = from cr in cumulativeresult
    orderby cr.Days
    select new
    {
        Days = cr.Days,
        Com = (from cr1 in cumulativeresult
            where cr1.Days < cr.Days
            group cr1 by 1 into cr1grp
            select
            new
            {
                Count = cr1grp.Count() + cr.Com 
            }),
        ComPercent = Math.Round((double.Parse((
            from cr1 in cumulativeresult
            where cr1.Days < cr.Days
            group cr1 by 1 into cr1grp 
            select cr1grp.Count() + cr.Com).ToString()) / ComCount) * 100, 2)
    };

But the Com and ComPercent are not coming as values. How will I be able to retrieve the value within them? My loop for retrieving them is as follows

Update

foreach (var item in result)
{
    dt.Rows.Add(item.Days, item.Com, item.ComPercent);
}

I do not want to do any processing on my foreach loop, I want the value in my linq query itself.

Compiler doesn't know your subquery will always return one row, since the return type is still IEnumerable (or IQueryable ). This can be solved by using First() or Single() (or the corresponding ..OrDefault() version), however, it is more common to just use Count() without grouping, for example :

Com = (from cr1 in cumulativeresult
       where cr1.Days < cr.Days
       select cr1
      ).Count() + cr.Com,

You might also want to consider moving the subquery into a let clause, so it can be reused to calculate Com and ComPercent :

var result = from cr in cumulativeresult
             let totalCount = 
                      (from cr1 in cumulativeresult
                       where cr1.Days < cr.Days
                       select cr1
                      ).Count() + cr.Com 
             orderby cr.Days
             select new
             {
                Days = cr.Days,
                Com = totalCount,
                ComPercent = Math.Round((double)totalCount / ComCount * 100, 2)
             };

To answer your question, you need to select the .First of what you, but not Linq, knows is a single grouping of 1 .

I've adjusted your query in a couple of other ways as well:

  1. To get some output I had to change the < to <= .
  2. I used a cast instead of reparsing as double.

This is the whole LinqPad query:

var cumulativeresult = new[] { new { Days = 0, Com = 0 }, new { Days = 1, Com = 1 } };
var ComCount = cumulativeresult.Count();
var result = from cr in cumulativeresult
             orderby cr.Days
             select new
             {
                 Days = cr.Days,
                 Com = (from cr1 in cumulativeresult
                        where cr1.Days <= cr.Days
                        group cr1 by 1 into cr1grp
                        select
                          new
                          {
                              Count = cr1grp.Count() + cr.Com
                          }
                           ).First().Count,
                 ComPercent = Math.Round((//double.Parse(
                           ((double)(
                           from cr1 in cumulativeresult
                           where cr1.Days <= cr.Days
                           group cr1 by 1 into cr1grp
                           select cr1grp.Count() + cr.Com).First())//.ToString())
                           / ComCount) * 100, 2
                           )
             };

var dt = new DataTable();
dt.Columns.AddRange(new[] {new DataColumn("Days"),new DataColumn("Com"),new DataColumn("ComPercent")  });
foreach (var item in result)
{
    dt.Rows.Add(item.Days, item.Com, item.ComPercent);
}
dt.Dump();

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