Linq ForEach()没有填充字段

时间:2014-09-10 16:56:03

标签: c# linq linq-to-entities

我在尝试使用ForEach()和linq计算模型上的3个字段时遇到问题。查询返回"活动"对于特定问题。其中一个字段是" TimeSpent",它是long。它基本上是花在该项目上的时间(以毫秒为单位)。我试图根据这个" TimeSpent"来显示日,小时和分钟。字段,用于每个活动。这是模特:

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();

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

4 个答案:

答案 0 :(得分: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 :(得分: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;

答案 2 :(得分:1)

这在任何意义上都是错误的。天,小时和分钟必须是只读属性,在内部从TimeSpent计算它们的值。您实施此方法的方式最终会导致您的对象无效数据。对于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}
}

答案 3 :(得分: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
              };