按连接和聚合分组(linq)

时间:2011-09-28 08:40:12

标签: c# linq orm

我遇到LINQ查询问题而且不知道如何解决它:/

我有两张桌子。一个是属性,第二个是属性行,但是我需要从行中总结几个小时并将其转换为属性;无法解释它;)这是我试图创建的查询:

var query = (from ta in session.db.TimesheetAttributes
             join tr in session.db.TimesheetRows on ta.Id equals tr.TimesheetAttributesId into tempTR
             from ttr in tempTR.DefaultIfEmpty()
             group ttr by new { ta.TimesheetId, ta.Date, ta.SickNote, ta.Vacation, ta.OccasionVacation } into g
             select new
             {
                 Id = g.Key.TimesheetId,
                 Date = g.Key.Date,
                 WeekDay = g.Key.Date.ToString("dddd", new CultureInfo("pl-PL")),
                 Description = String.Format("{0:dd/MM/yyyy}", g.Key.Date),
                 SickNote = g.Key.SickNote,
                 Vacation = g.Key.Vacation,
                 OccasionVacation = g.Key.OccasionVacation,
                 Hours = String.Format("{0:HH:mm}", (new DateTime(g.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))
             }).OrderBy(c=>c.Date).ToList();

问题在于并非每个属性都有行,这就是我尝试使用DefaultIfEmpty()的原因,但是这个查询无效:(

我的旧查询正在运行,但是我的ORM为每一行创建了一个新查询,因此,如果我有1000个TimesheetAttributes,则会选择1000:/

这是我的旧查询:

var query = (from c in session.db.TimesheetAttributes
             where ((c.Active == true)
                    && (c.Timesheet.Active == true)
                    && (c.ValidFrom <= validDate)
                    && (c.ValidTo > validDate)
                    && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId))
             select new
             {
                 Id = c.TimesheetId,
                 c.Date,
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")),
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date),
                 Hours = String.Format("{0:HH:mm}", (new DateTime((c.TimesheetRows.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))),
                 c.SickNote,
                 c.Vacation,
                 c.OccasionVacation
              }).OrderBy(c => c.Date).ToList();

编辑:

这是我得到的异常:&#34;调用的目标抛出了异常&#34; InnerException:&#34;对象引用未设置为对象的实例&#34;

1 个答案:

答案 0 :(得分:0)

您使用旧查询时遇到的问题通常被称为n+1 problem

您应该能够调整原始查询,如下所示:

var query = (from c in session.db.TimesheetAttributes 
             from cr in c.TimesheetRows
             where ((c.Active == true) 
                    && (c.Timesheet.Active == true) 
                    && (c.ValidFrom <= validDate) 
                    && (c.ValidTo > validDate) 
                    && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId)) 
             select new 
             { 
                 Id = c.TimesheetId, 
                 c.Date, 
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")), 
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date), 
                 Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))), 
                 c.SickNote, 
                 c.Vacation, 
                 c.OccasionVacation 
              }).OrderBy(c => c.Date).ToList(); 

如果仍然发出声音,您可以尝试在Ten属性中添加一个tenary运算符......

Hours = String.Format("{0:HH:mm}", !(cr == null) && cr.Any() ? (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks))) : DateTime.MinValue

编辑:

我明白你的意思,我的脑子还没有醒来。您遇到的问题是底层查询提供程序没有注意到它需要获取TimesheetAttributes和关联/相关的TimesheetRows。这可能是因为TimesheetRows深埋在生成您正在选择的匿名类型的表达式中。

我的查询语法并不精彩(我更喜欢在lambda中这样做 - 我觉得它更像未来证明但这只是一种感觉),但我会试一试......

var query = (from res in 
                 (from c in session.db.TimesheetAttributes           
                 where ((c.Active == true)           
                        && (c.Timesheet.Active == true)           
                        && (c.ValidFrom <= validDate)           
                        && (c.ValidTo > validDate)           
                        && (c.Timesheet.ContactPersonId == session.ContactPersonAttributes.ContactPersonId))           
                 select new           
                 {   
                     c = c,
                     cr = c.TimesheetRows
                 })
             select new
             {
                 Id = c.TimesheetId,           
                 c.Date,           
                 WeekDay = c.Date.ToString("dddd", new CultureInfo("pl-PL")),           
                 Description = String.Format("{0:dd/MM/yyyy}", c.Date),           
                 Hours = String.Format("{0:HH:mm}", (new DateTime((cr.Aggregate(TimeSpan.Zero, (subtotal, t) => subtotal + (t.DateTo - t.DateFrom)).Ticks)))),           
                 c.SickNote,           
                 c.Vacation,           
                 c.OccasionVacation           
              }).OrderBy(c => c.Date).ToList();  

它看起来比原版更丑,我确信有更好的方法,但它应该使表达式足够清楚,以便您的查询提供程序(L2S或其他)实现它需要返回两个实体,并且避免n + 1问题。