LINQ to Objects Join two collections to set values in the first collection

那年仲夏 提交于 2020-06-24 19:34:26

问题


I have the following Entity Framework query:

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

I'm using AutoMapper to map to another type:

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

In my Objects.Result type, I have a property called reason that is not coming from the database. It is coming from another source that I need to basically populate back into my mapped type:

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

I need to join the reasons with my mapped collection and set the Reason property in my mapped collection using the value from my reasons collection. Is this possible?

 // 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;

Obviously the above code doesn't compile, but is there code I can write that does what I want?


回答1:


Do the mutation in a loop. Optimally, Linq should be free of mutations to the collection(s) it operates against. Use Linq to filter, order, project your data, use traditional techniques to modify.

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



回答2:


This may save lot of your time. Below code is for Join two collections and to set property value of first collection.

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



回答3:


One brute force method would be:-

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

In fact, this is implementation is quite close to your pseudo-code.




回答4:


Linq shouldn't be used to mutate the object. Having said that, from the performance standpoint, I don't like the extra loop that the "foreach" solution requires either.

So, this is my solution:

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

Although it's not pure linq, I think it's pretty clear that a side effect will be performed and there is not extra looping and no extra unnecessary new objects instantiated.



来源:https://stackoverflow.com/questions/8127430/linq-to-objects-join-two-collections-to-set-values-in-the-first-collection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!