LinqForEach()未填充字段

本文关键字:填充 字段 LinqForEach | 更新日期: 2023-09-27 18:21:20

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

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

我得到结果中的所有其他字段,但"天"、"小时"answers"分钟"均为0。我不太确定我做错了什么。感谢您的帮助。

LinqForEach()未填充字段

首先将列表存储到变量中,然后使用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不会返回列表,而是对其进行更改。因此,您必须将列表放入一个变量中,进行更改,然后返回修改后的列表。

这在任何意义上都是错误的。Days、Hours和Minutes必须是只读属性,这些属性从内部的TimeSpend计算其值。实现这一点的方式可能会导致对象中出现无效数据。例如:

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}
}

@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;
  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
              };