LINQ:如何在投影中清空属性?

时间:2014-04-22 04:52:16

标签: c# linq entity-framework

标题非常糟糕,所以让我试着用代码解释一下。我有一个名为Change的实体,它有一个ChangeDetail个实体的集合。我想将Change个实体的集合投影到名为ChangeListItem的DTO。我一直在搞乱LINQPad,我实际上已完成投影并按照我的意愿工作,但我无法工作的是取消组中的所有ChangeListItem除外第一个。这是我的代码:

更改

public class Change : {
    public DateTime ChangedDateTime { get; set; }

    #region Navigation Properties
    public virtual ICollection<ChangeDetail> Details { get; private set; }
    #endregion

    public Change() {
        this.Details = new List<ChangeDetail>();
    }
}

ChangeDetail

public class ChangeDetail {
    public string Details { get; set; }

    #region Navigation Properties
    public int ChangeId { get; set; }

    public virtual Change Change { get; set; }
    #endregion
}

我的LINQPad尝试

var changes =
    Changes
        .SelectMany(c => c.Details)
        .OrderByDescending(c => c.Change.ChangedDateTime)
        .Select(c => new ChangeListItem
        {
            ChangedDateTime = c.Change.ChangedDateTime,
            Details = c.Details
        })
        .GroupBy(c => c.ChangedDateTime)
        .ForEach(g =>
        {
            g
                .Skip(1)
                .ForEach(c =>
                {
                    c.ChangedDateTime = null;
                });
        });

当我将其转储到结果窗格中时,我仍然会收到ChangeListItem组的集合,但ChangedDateTime属性仍然填写完整。我确定我错过了一路上的重新分配,即使我认为我所做的那个应该足够好。我怎样才能得到我想要的东西?

我想离开这个:

enter image description here

对此:

enter image description here

更新根据此处的要求,ForEach扩展程序的代码为:

public static class IQueryableExtensions {
    public static IQueryable<T> ForEach<T>(
        this IEnumerable<T> source,
        Action<T> action) {
        if (source == null) {
            throw new ArgumentNullException("source");
        }

        if (action == null) {
            throw new ArgumentNullException("action");
        }

        foreach (T t in source) {
            action(t);
        }

        return source.AsQueryable<T>();
    }
}

1 个答案:

答案 0 :(得分:5)

您正在处理LINQ 查询,就像它是集合一样。我假设您的ForEach扩展名如下:

foreach(var item in source)
{
    SideEffect(item);
}

return source;

此处查询查询结果一次,并且每个结果项都会发生变异。但是当你再次枚举查询时,其结果是从头开始重新创建;因此,突变就会丢失。

理论上,可以在代码中包含一些策略性ToList()调用以获得所需的效果。但这并非符合LINQ的精神。不要混合LINQ和副作用。如果你想有条件地投射一些物品而不让其他物品保持不变,那么就这样做:

changeGroup.Select( (c, index) => index == 0 ? c : new ChangeListItem 
                    { 
                        ChangedDateTime = null,
                        Details = c.Details
                    } );

顺便说一下,在执行此转换之前,您可能需要调用AsEnumerable(),因为我不认为LINQ to Entities支持包含项目索引的Select的重载(可以&#39;尽管如此,我还记得了。