2014-09-10 131 views
2

我无法使用ForEach()和linq来计算我的模型中的3个字段。查询返回特定问题的“活动”。其中一个领域是“TimeSpent”,这是一个long。基本上是以毫秒为单位花费在这个项目上的时间。我试图根据每个活动的“TimeSpent”字段显示Days,Hours和Minutes。这里的型号:Linq ForEach()不填充字段

public class ActivityGridModel 
{ 
    public DateTime ActivityDate { get; set; } 
    public string ActivityType { get; set; } 
    public string Notes { get; set; } 
    public string EnteredBy { get; set; } 
    public long TimeSpent { get; set; } 
    public int Days { get; set; } 
    public int Hours { get; set; } 
    public int Minutes { get; set; } 
} 

这是我建立查询:

var activities = from a in Session.Context.Activities 
        join at in Session.Context.ActivityTypes 
        on a.ActivityTypeID equals at.ActivityTypeID 
        join u in Session.Context.Users 
        on a.CreatedByUserID equals u.UserID 
        where a.IssueID == issueId 
        select new ActivityGridModel() 
        { 
         ActivityDate = a.ActivityDate, 
         ActivityType = at.ActivityType1, 
         Notes = a.Notes, 
         EnteredBy = u.FirstName + " " + u.LastName, 
         TimeSpent = a.TimeSpent 
        }; 

这里的地方我尝试填充天数,小时,和我的模型纪要:

activities.ToList().ForEach(a => 
{ 
    TimeSpan timeSpent = new TimeSpan(a.TimeSpent); 
    a.Days = timeSpent.Days; 
    a.Hours = timeSpent.Hours; 
    a.Minutes = timeSpent.Minutes; 
}); 

return activities.ToList(); 

我得到了结果中的所有其他字段,但Days,Hours和Minutes都是0.我不太确定我做错了什么。任何帮助表示赞赏。

回答

1

这是错误在任何意义。天数,小时数和分钟数必须是只读的属性,可以从TimeSpent内部计算它们的值。你已经实现了这个方法,你可以在你的objet中得到无效的数据。对于exapmle:

var model = new ActivityGridModel { TimeSpent = X }; 
model.Days = 5; 
model.Hours = 10; 

这是有效的吗?

一个更好的办法是计算天数,小时和分钟内:

public class ActivityGridModel 
{ 
    public DateTime ActivityDate { get; set; } 
    public string ActivityType { get; set; } 
    public string Notes { get; set; } 
    public string EnteredBy { get; set; } 
    private long _timeSpent; 
    public long TimeSpent 
    { 
     get 
     { 
      return _timeSpent; 
     } 
     set 
     { 
      _timeSpent = value; 
      var tsSpent = new TimeSpan(_timeSpent); 
      Days = tsSpent .Days; 
      Hours = tsSpent .Hours; 
      Minutes = tsSpent .Minutes; 
     } 
    } 
    public int Days { get; private set; //readonly for class clients } 
    public int Hours { get; private set; //readonly for class clients} 
    public int Minutes { get; private set; //readonly for class clients} 
} 
+0

虽然@ Selman22答案的作品是正确的,我决定使用这个解决方案,因为brz是正确的,这些领域应该内部计算。 – Robert 2014-09-11 14:11:12

2

第一家门店列表到一个变量,然后使用Foreach

var activityList = activities.ToList(); 
activityList.ForEach(a => 
{ 
    TimeSpan timeSpent = new TimeSpan(a.TimeSpent); 
    a.Days = timeSpent.Days; 
    a.Hours = timeSpent.Hours; 
    a.Minutes = timeSpent.Minutes; 
}); 
return activityList; 

你是第一个执行查询(用.ToList()),所创建的列表上使用ForEach但你扔掉该列表。

然后,您再次执行相同的查询并将结果作为列表返回,而无需进行任何修改,这使得ForEach毫无意义。

Linq查询是懒惰评估。因此,每次执行查询时都会得到一个新列表。

这里重要的是ForEach不返回列表,它改变它。所以你必须把这个列表放入一个变量中,进行修改然后返回修改后的列表。

+1

这将是值得向大家解释*这是必需的原因。 – 2014-09-10 16:59:50

+0

@JonSkeet足够清楚了吗? – 2014-09-10 17:12:32

+0

是的,那绝对会更好。 – 2014-09-10 17:15:07

0
var activities = from a in Session.Context.Activities 
       join at in Session.Context.ActivityTypes 
       on a.ActivityTypeID equals at.ActivityTypeID 
       join u in Session.Context.Users 
       on a.CreatedByUserID equals u.UserID 
       where a.IssueID == issueId 
       select new ActivityGridModel() 
       { 
        ActivityDate = a.ActivityDate, 
        ActivityType = at.ActivityType1, 
        Notes = a.Notes, 
        EnteredBy = u.FirstName + " " + u.LastName, 
        TimeSpent = a.TimeSpent, 
        Days = a.TimeSpent.Days, 
        Hours = a.TimeSpent.Hours, 
        Minutes = a.TimeSpent.Minutes 
       }; 
+0

这与OP的代码没有做同样的事,你不能像OP的代码那样做,因为DB不能把它转换成SQL。 – Servy 2014-09-10 17:17:51

1

@ Selman22有解决方案,但这就是代码无法正常工作的原因。

对活动的原始分配显示为可能为IQueryable<ActivityGridModel>,因此在其上执行.ToList()两次会有效地创建两组数据。第一个列表被更新,然后像@ Selman22说它被扔掉了。第二个列表是一组未更新的新数据。

除了冗余创建之外,它看起来像它会在上下文中执行两次枚举,这可能也很昂贵。请记住,您应该减少对昂贵的方法的调用次数。它可能看起来没有太多的执行,但可能有一个抽象层从磁盘,数据库或Web服务读取/写入数据。

这里是什么// @ Selman22说,有关解决方案的一个重复:

var activityList = activities.ToList(); 
activityList.ForEach(a => 
{ 
    TimeSpan timeSpent = new TimeSpan(a.TimeSpent); 
    a.Days = timeSpent.Days; 
    a.Hours = timeSpent.Hours; 
    a.Minutes = timeSpent.Minutes; 
}); 
return activityList;