public partial class Objective{ public Objective() { this.ObjectiveDetails = new List<ObjectiveDetail>(); } public int ObjectiveId { get; set; } public int Number { get; set; } public virtual ICollection<ObjectiveDetail> ObjectiveDetails { get; set; } } public partial class ObjectiveDetail { public ObjectiveDetail() { this.SubTopics = new List<SubTopic>(); } public int ObjectiveDetailId { get; set; } public int Number { get; set; } public string Text { get; set; } public virtual ICollection<SubTopic> SubTopics { get; set; } } public partial class SubTopic { public int SubTopicId { get; set; } public string Name { get; set; } }
我有两个列表:
IList<ObjectiveDetail> oldObj; IList<ObjectiveDetail> newObj;
以下LINQ给出了一个新的ObjectiveDetail对象列表,其中:列表中的任何ObjectiveDetail对象的Number或Text字段在oldObj和newObj之间是不同的.
IList<ObjectiveDetail> upd = newObj .Where(wb => oldObj .Any(db => (db.ObjectiveDetailId == wb.ObjectiveDetailId) && (db.Number != wb.Number || !db.Text.Equals(wb.Text)))) .ToList();
我如何修改它,以便LINQ给我一个新的ObjectiveDetail对象列表,其中:列表中的任何ObjectiveDetail对象的Number或Text字段或SubTopic集合在oldObj和newObj之间是不同的.
换句话说,我想要一个ObjectiveDetail被添加到upd列表如果:
>它在oldObj中的文本与newObj中的文本不同
>它的oldObj中的Number与newObj中的Number不同
>它有一个SubTopics集合,在oldObj中有三个元素,在newObj中有4个元素
>它有一个SubTopics集合,在oldObj中没有元素,在newObj中没有2个元素
>它有一个SubTopics集合,在oldObj中有2个元素,在newObj中没有元素
>它有一个SubTopics集合,其中SubTopicId的元素在oldObj中为1和2,在newObj中为1和3
我希望有人可以提出我已经拥有的LINQ语句中的一些额外的一行.
解决方法
IList<ObjectiveDetail> upd = newObj.Where(wb => oldObj.Any(db => (db.ObjectiveDetailId == wb.ObjectiveDetailId) && (db.Number != wb.Number || !db.Text.Equals(wb.Text) || db.SubTopics.Count != wb.SubTopics.Count || !db.SubTopics.All(ds => wb.SubTopics.Any(ws => ws.SubTopicId == ds.SubTopicId)) ))).ToList();
怎么运行的
db.SubTopics.Count!= wb.SubTopics.Count确认正在比较的新对象(wb)和被比较的旧对象(db)具有相同数量的SubTopics.那部分是非常简单的.
!db.SubTopics.All(ds => wb.SubTopics.Any(ws => ws.SubTopicId == ds.SubTopicId))有点复杂.如果给定的表达式对于集合的所有成员都为true,则All()方法返回true.如果给定的表达式对于集合中的任何成员都为true,那么Any()方法返回true.因此,整个表达式检查对于旧对象db中的每个SubTopic ds,在新对象wb中是否存在具有相同ID的Subtopic ws.
基本上,第二行确保在旧对象中存在的每个SubTopic也存在于新对象中.第一行确保旧的&新对象具有相同数量的SubTopics;否则第二行将考虑使用SubTopics 1& amp; 2与SubTopics 1,2,& 3.
注意事项
此添加不会检查SubTopics是否具有相同的名称;如果还需要检查,那么将第二行中的ws.SubTopicId == ds.SubTopicId更改为ws.SubTopicId == ds.SubTopicId&&& ws.Name.Equals(ds.Name).
如果ObjectiveDetail可以包含多个具有相同SubTopicId的SubTopic(即,如果SubTopicIds不是唯一的),则此添加将无法正常工作.如果是这样,您需要用第二行替换db.SubTopics.All(ds => db.SubTopics.Count(ds2 => ds2.SubTopicId == ds.SubTopicId)== wb.SubTopics.Count (ws => ws.SubTopicId == ds.SubTopicId)).这将检查每个SubTopicId在新对象中的显示格式与旧对象中的完全一样多.
这个添加将不会检查SubTopics中的新对象&旧对象的顺序相同.为此,您将需要用db.SubTopics.Where((ds,i)=> ds.SubTopicId == wb.SubTopics [i] .SubTopicId).Count!= db.SubTopics.Count替换第二行.请注意,此版本还处理非唯一的SubTopicId值.它确认了旧对象中SubTopics的数量,使得新对象中相同位置的SubTopic相同等于旧对象中SubTopics的总数(也就是说,对于旧对象中的每个SubTopic,SubTopic在新对象中的相同位置是一样的).
高层思想
从可维护的角度来看,康拉德·科科萨(Konrad Kokosa)的答案是更好的(我已经被提拔了).如果您不期望需要经常重新访问该语句,我将只使用这样一个很丑的LINQ语句.如果您认为决定两个ObjectiveDetail对象是否相等的方式可能会更改,或者使用此语句的方法可能需要重新工作,否则该方法至关重要,因为第一次查看代码的新用户需要能够快速了解它,那么不要使用大长串的LINQ.