Linq ForEach()不填充字段
我无法使用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.我不太确定我做错了什么。任何帮助表示赞赏。
这是错误在任何意义。天数,小时数和分钟数必须是只读的属性,可以从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}
}
第一家门店列表到一个变量,然后使用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
不返回列表,它改变它。所以你必须把这个列表放入一个变量中,进行修改然后返回修改后的列表。
这将是值得向大家解释*这是必需的原因。 – 2014-09-10 16:59:50
@JonSkeet足够清楚了吗? – 2014-09-10 17:12:32
是的,那绝对会更好。 – 2014-09-10 17:15:07
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
};
这与OP的代码没有做同样的事,你不能像OP的代码那样做,因为DB不能把它转换成SQL。 – Servy 2014-09-10 17:17:51
@ 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;
虽然@ Selman22答案的作品是正确的,我决定使用这个解决方案,因为brz是正确的,这些领域应该内部计算。 – Robert 2014-09-11 14:11:12