问题
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