一个LINQ语句将返回答案而不会破坏它

时间:2017-07-28 04:04:43

标签: c# linq

我正在研究一个需要做一些计数和分组的问题。我曾尝试在工作中这样做,但无法在一个查询中执行此操作。当然,我可以将其拆分并得到答案,但我很好奇是否有人可以帮助我在一个声明中找到答案?

以下是我需要的代码和答案。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace GetCountInfo
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            /*
             * 
             * 
             * current Date would be: 7/27/2017 4:00 PM
             * 
            ReportOutOfDateCountDto

            The answer would be: 

            Patrick = Count of 1
            Stacy = Count of 2

            */
        }

        /// <summary>
        /// This is the data for each year nbr
        /// </summary>
        /// <returns></returns>
        public IList<YearNbrInfoDto> GetYearInfoData()
        {
            IList<YearNbrInfoDto> theData = new List<YearNbrInfoDto>();

            theData.Add(new YearNbrInfoDto { RecordId = 1, YearNbr = 0, CreateDt = new DateTime(2014,1,6) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 1, YearNbr = 1, CreateDt = new DateTime(2014, 5, 6) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 1, YearNbr = 2, CreateDt = new DateTime(2015, 1, 22) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 1, YearNbr = 3, CreateDt = new DateTime(2018, 5, 6) }); // NOT out of date

            // Above would just be a count of 1 because there are 3 that are out of date, but they all have the same record id, so it would just be 1 record id

            theData.Add(new YearNbrInfoDto { RecordId = 2, YearNbr = 0, CreateDt = new DateTime(2019, 5, 6) }); // NOT out of date
            theData.Add(new YearNbrInfoDto { RecordId = 2, YearNbr = 1, CreateDt = new DateTime(2018, 1, 6) }); // NOT out of date

            // Above would not be calculated because none of the Record Ids are out of date

            theData.Add(new YearNbrInfoDto { RecordId = 5, YearNbr = 0, CreateDt = new DateTime(2014, 3, 3) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 5, YearNbr = 1, CreateDt = new DateTime(2015, 3, 6) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 5, YearNbr = 2, CreateDt = new DateTime(2017, 10, 3) }); // NOT out of date
            theData.Add(new YearNbrInfoDto { RecordId = 5, YearNbr = 3, CreateDt = new DateTime(2018, 1, 6) }); // NOT out of date

            // Above would just be a count of 1 because there are 2 that are out of date, but they all have the same record id, so it would just be 1 record id

            theData.Add(new YearNbrInfoDto { RecordId = 6, YearNbr = 0, CreateDt = new DateTime(2014, 3, 3) }); // out of date
            theData.Add(new YearNbrInfoDto { RecordId = 6, YearNbr = 1, CreateDt = new DateTime(2018, 3, 6) }); // NOT out of date
            theData.Add(new YearNbrInfoDto { RecordId = 6, YearNbr = 2, CreateDt = new DateTime(2019, 1, 3) }); // NOT out of date
            theData.Add(new YearNbrInfoDto { RecordId = 6, YearNbr = 3, CreateDt = new DateTime(2020, 1, 6) }); // NOT out of date

            // Above would just be a count of 1 because there is 1 that is out of date

            return theData;
        }

        /// <summary>
        /// This ties the Year Record info to the user ids
        /// </summary>
        /// <returns></returns>
        public IList<MainRecordInfoDto> GetMainRecordInfoData()
        {
            IList<MainRecordInfoDto> theData = new List<MainRecordInfoDto>();

            theData.Add(new MainRecordInfoDto { UserId = 1, RecordId = 1 });
            theData.Add(new MainRecordInfoDto { UserId = 1, RecordId = 2 });
            theData.Add(new MainRecordInfoDto { UserId = 1, RecordId = 3 });
            theData.Add(new MainRecordInfoDto { UserId = 1, RecordId = 4 });


            theData.Add(new MainRecordInfoDto { UserId = 2, RecordId = 5 });
            theData.Add(new MainRecordInfoDto { UserId = 2, RecordId = 6 });

            return theData;
        }

        /// <summary>
        /// This is the main User info...
        /// </summary>
        /// <returns></returns>
        public IList<UserInfoDto> GetUserInfoData()
        {
            IList<UserInfoDto> theData = new List<UserInfoDto>();

            theData.Add(new UserInfoDto { Name = "Patrick", UserId = 1 });
            theData.Add(new UserInfoDto { Name = "Stacy", UserId = 2 });

            return theData;
        }
    }

    public class ReportOutOfDateCountDto
    {
        public string Name { get; set; }

        /// <summary>
        /// This would be the count of out of date PER RecordId
        /// </summary>
        public int CountOfOutOfDateYearNbrs { get; set; }

    }

    public class YearNbrInfoDto
    {

        public int RecordId { get; set; }

        public int YearNbr { get; set; }

        public DateTime CreateDt { get; set; }
    }

    public class MainRecordInfoDto
    {
        public int UserId { get; set; }

        public int RecordId { get; set; }
    }

    public class UserInfoDto
    {
        public string Name { get; set; }
        public int UserId { get; set; }
    }
}

2 个答案:

答案 0 :(得分:1)

您可以加入关系数据,以获得更短,更高效的查询:

var result = GetYearInfoData()
    .Where(d => d.CreateDt < DateTime.Now)
    .Select(x => x.RecordId)                                   // RecordIds 1, 1, 1, 5, 5, 6
    .Distinct()                                                         // RecordIds 1, 5, 6
    .Join(GetMainRecordInfoData(), i => i, r => r.RecordId, (i, r) => r.UserId)  // UserIds 1, 2, 2
    .Join(GetUserInfoData()      , i => i, u => u.UserId  , (i, u) => u.Name  )  // Names { Patrick, Stacy, Stacy }
    .GroupBy(n => n)
    .Select(g => new { Name = g.Key, Count = g.Count() });  // Names and Counts

如果数据不是来自数据库,则可以通过在查询之前创建查找来进一步优化数据:

var yearLookup = GetYearInfoData().ToLookup(y => y.RecordId);
var recordLookup = GetMainRecordInfoData().ToLookup(r => r.UserId);

var result = GetUserInfoData().Select(u => new { u.Name, Count = recordLookup[u.UserId]
    .Count(i => yearLookup[i.RecordId].Any(d => d.CreateDt < DateTime.Now)) });

答案 1 :(得分:0)

所以我觉得我得到了答案,但真的不明白怎么做。请看下面:

var tblYearInfoData = GetYearInfoData();

var tblMainRecordInfoData = GetMainRecordInfoData();

var tblGetUserInfoData = GetUserInfoData();

var thisWillNeverWork = (from yfd in tblYearInfoData
                        where yfd.CreateDt < DateTime.Now // Pull all the record ids where the create dt is out of date... i.e.  in the past...
                        select new
                        {
                            RecordId = yfd.RecordId  // Select those record ids....
                        })
                        .GroupBy(gb => gb.RecordId) // Now group by the record ids... so if there is one record id.... and there are 3 that are out of date... it will combine it to 1...
                        .Select(selectGroup1 => new
                        {
                           RecordId = selectGroup1.Key, // This will get the grouped by record ids...

                            // Get the User Id so then we can do a final count with the name
                            UserId = tblMainRecordInfoData.Where(w => w.RecordId == selectGroup1.Key).Select(s => s.UserId).FirstOrDefault() 
                        }).GroupBy(gb => gb.UserId) // Then we group by user id....
                          .Select(selectGroup2 => new ReportOutOfDateCountDto
                          {
                             Name = tblGetUserInfoData.Where(w => w.UserId == selectGroup2.Key).Select(s => s.Name).FirstOrDefault(),  // we use the user id grouped by... to get the name
                             CountOfOutOfDateYearNbrs = selectGroup2.Count()  // then we do a count on the group by and somehow it worked... haha not sure how :-)
                          }).ToList();