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。我不太确定我做错了什么。感谢您的帮助。
首先将列表存储到变量中,然后使用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
};