连接两个集合以在第一个集合中设置值

本文关键字:集合 第一个 设置 连接 两个 | 更新日期: 2023-09-27 18:14:28

我有以下实体框架查询:

var results = from r in db.Results
              select r;

我正在使用AutoMapper映射到另一个类型:

var mapped = Mapper.Map<IEnumerable<Database.Result>, IEnumerable<Objects.Result>>(results);

在我的对象。结果类型,我有一个属性称为原因,不是来自数据库。它来自另一个源,我需要将其填充回映射类型:

var reasons = new List<Reason>
{
    new Reason { Id = 1, Reason = "asdf..." }
};

我需要将原因与映射集合连接起来,并使用来自原因集合的值在映射集合中设置Reason属性。这可能吗?

 // need something like this:
 mapped = from m in mapped
          join r in reasons on m.Id equals r.Id
          update m.Reason = r.Reason
          select m;

显然上面的代码不编译,但有代码我可以写,做我想要的吗?

连接两个集合以在第一个集合中设置值

在循环中进行突变。最理想的情况是,Linq应该不会对它所操作的集合产生任何变化。使用Linq来过滤,排序,投影你的数据,使用传统的技术来修改。

var joinedData = from m in mapped 
                 join r in reasons on m.Id equals r.Id 
                 select new { m, r };
foreach (var item in joinedData)
{
    item.m.Reason = item.r.Reason;
}

这样可以节省很多时间。下面的代码用于连接两个集合并设置第一个集合的属性值。

class SourceType
{
    public int Id;
    public string Name;
    public int Age { get; set; }
    // other properties
}
class DestinationType
{
    public int Id;
    public string Name;
    public int Age { get; set; }
    // other properties
}
    List<SourceType> sourceList = new List<SourceType>();
    sourceList.Add(new SourceType { Id = 1, Name = "1111", Age = 35});
    sourceList.Add(new SourceType { Id = 2, Name = "2222", Age = 26});
    sourceList.Add(new SourceType { Id = 3, Name = "3333", Age = 43});
    sourceList.Add(new SourceType { Id = 5, Name = "5555", Age = 37});
    List<DestinationType> destinationList = new List<DestinationType>();
    destinationList.Add(new DestinationType { Id = 1, Name = null });
    destinationList.Add(new DestinationType { Id = 2, Name = null });
    destinationList.Add(new DestinationType { Id = 3, Name = null });
    destinationList.Add(new DestinationType { Id = 4, Name = null });

    var mapped= destinationList.Join(sourceList, d => d.Id, s => s.Id, (d, s) =>
    {
        d.Name = s.Name;
        d.Age = s.Age;
        return d;
    }).ToList();

一种蛮力方法是:-

foreach(var m in mapped)
{
    m.Reason = reasons.Single(r=> r.Id == m.Id).Reason;
}

实际上,这是非常接近你的伪代码的实现。

Linq不应该被用来改变对象。话虽如此,从性能的角度来看,我也不喜欢"foreach"解决方案所需要的额外循环。

所以,这是我的解决方案:

Func<ObjectType, AnotherType, ObjectType> Fill = delegate (ObjectType x, AnotherType a)
{
    x.SomeProperty = a;
    x.Date = DateTime.Now;
    return x;
};
var result = from source in sources
             join anotherSource in otherSource on source.Id equals anotherSource.Id
             select Fill(source, anotherSource);

虽然这不是纯粹的linq,但我认为很明显会产生副作用并且没有额外的循环,也没有额外的不必要的新对象实例化。