C# 在比较两个集合时,如何从LINQ更改为使用简单的foreach?
我有以下代码,我觉得非常混乱。代码所做的是比较两个集合中的数据,然后根据oldObj和newObj之间的更改发布更新、添加或删除 有没有一种方法可以简化它,使它只包含在三个foreach循环中,这样我就不必使用奇特的LINQ代码。如果有人能给我一个建议,我可以做的第一个变化,只是增加,然后即使是将是一个很大的帮助C# 在比较两个集合时,如何从LINQ更改为使用简单的foreach?,c#,C#,我有以下代码,我觉得非常混乱。代码所做的是比较两个集合中的数据,然后根据oldObj和newObj之间的更改发布更新、添加或删除 有没有一种方法可以简化它,使它只包含在三个foreach循环中,这样我就不必使用奇特的LINQ代码。如果有人能给我一个建议,我可以做的第一个变化,只是增加,然后即使是将是一个很大的帮助 var oldObj = db.SubTopics .Where(t => t.TopicId == id) .AsNoTracking() .ToList(); v
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
var upd = newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))))
.ToList();
var add = newObj
.Where(wb => oldObj
.All(db1 => db1.SubTopicId != wb.SubTopicId))
.ToList();
var del = oldObj
.Where(db1 => newObj
.All(wb => wb.SubTopicId != db1.SubTopicId))
.ToList();
foreach (var subTopic in upd)
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
foreach (var subTopic in add)
{
db.SubTopics.Add(subTopic);
}
foreach (var subTopic in del)
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
如注释中所述,
Where
到foreach
的转换非常简单
前两个linq查询(oldObj
和newObj
变量)只是从数据库中选择数据,它们必须保持不变`最后的ToList()表示我们正在对数据库执行查询并实际检索数据
第一句话:
var upd = newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))))
.ToList();
表示“从newObj
集合中获取同样位于oldObj
中且其至少一个属性已更改的对象”。使用foreach,它将是:
var upd = new List<SubTopic>();
foreach(var newObjElement in newObj) {
bool wasUpdated = false;
foreach(var oldObjEl in oldObj) {
if (oldObjEl.SubTopicId == wb.SubTopicId
&& (db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))) {
wasUpdated = true;
break;
}
if (wasUpdated) upd.Add(newObjElement);
}
}
变成:
var add = new List<SubTopic>();
foreach(var newObjElement in newObj) {
bool wasAdded = true;
foreach(var oldObjEl in oldObj) {
if (oldObjEl.SubTopicId != wb.SubTopicId) {
// do nothing
}
else {
wasAdded = false;
break;
}
if (wasAdded) add.Add(newObjElement);
}
}
var add=new List();
foreach(newObj中的var newobjeelement){
bool wasAdded=true;
foreach(oldObj中的var oldObjEl){
if(oldObjEl.SubTopicId!=wb.SubTopicId){
//无所事事
}
否则{
wasAdded=false;
打破
}
如果(wasAdded)add.add(newObjElement);
}
}
而del
类似于add
虽然这种转换是可能的,但我强烈反对这样做。
linq
版本确实更具可读性。这就是linq设计的目的。将Where
转换为foreach
非常简单,如评论中所述
前两个linq查询(oldObj
和newObj
变量)只是从数据库中选择数据,它们必须保持不变`最后的ToList()表示我们正在对数据库执行查询并实际检索数据
第一句话:
var upd = newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))))
.ToList();
表示“从newObj
集合中获取同样位于oldObj
中且其至少一个属性已更改的对象”。使用foreach,它将是:
var upd = new List<SubTopic>();
foreach(var newObjElement in newObj) {
bool wasUpdated = false;
foreach(var oldObjEl in oldObj) {
if (oldObjEl.SubTopicId == wb.SubTopicId
&& (db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))) {
wasUpdated = true;
break;
}
if (wasUpdated) upd.Add(newObjElement);
}
}
变成:
var add = new List<SubTopic>();
foreach(var newObjElement in newObj) {
bool wasAdded = true;
foreach(var oldObjEl in oldObj) {
if (oldObjEl.SubTopicId != wb.SubTopicId) {
// do nothing
}
else {
wasAdded = false;
break;
}
if (wasAdded) add.Add(newObjElement);
}
}
var add=new List();
foreach(newObj中的var newobjeelement){
bool wasAdded=true;
foreach(oldObj中的var oldObjEl){
if(oldObjEl.SubTopicId!=wb.SubTopicId){
//无所事事
}
否则{
wasAdded=false;
打破
}
如果(wasAdded)add.add(newObjElement);
}
}
而del
类似于add
虽然这种转换是可能的,但我强烈反对这样做。
linq
版本确实更具可读性。这就是linq设计的目的。好的。让我们先通过去除任何积垢来简化您所拥有的。您有一些.ToList()
调用只使用过一次的集合,因此它们只是额外的代码,除了浪费时间和内存外什么也不做。让我们把它们排除在干扰之外:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
var upd = newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))));
var add = newObj
.Where(wb => oldObj
.All(db1 => db1.SubTopicId != wb.SubTopicId));
var del = oldObj
.Where(db1 => newObj
.All(wb => wb.SubTopicId != db1.SubTopicId));
foreach (var subTopic in upd)
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
foreach (var subTopic in add)
{
db.SubTopics.Add(subTopic);
}
foreach (var subTopic in del)
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
现在,让我们将它们移动到foreach
的主体中:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes)))))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
foreach (var subTopic in newObj
.Where(wb => oldObj
.All(db1 => db1.SubTopicId != wb.SubTopicId)))
{
db.SubTopics.Add(subTopic);
}
foreach (var subTopic in oldObj
.Where(db1 => newObj
.All(wb => wb.SubTopicId != db1.SubTopicId)))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
现在让我们将.Where()
作为foreach
逻辑的一部分:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj)
{
if(oldObj.Any(db1 => (db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes))))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
}
foreach (var subTopic in newObj)
{
if(oldObj.All(db1 => db1.SubTopicId != subTopic.SubTopicId))
{
db.SubTopics.Add(subTopic);
}
}
foreach (var subTopic in oldObj)
{
if(newObj.All(subTopic.SubTopicId != db1.SubTopicId))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
现在让我们将.Any()
实现为一个循环:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if((db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes)))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
break;
}
}
}
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if(db1 => db1.SubTopicId != subTopic.SubTopicId)
{
db.SubTopics.Add(subTopic);
break;
}
}
}
foreach (var subTopic in oldObj)
{
if(newObj.All(subTopic.SubTopicId != db1.SubTopicId)))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
现在,让我们对All()
执行相同的操作:
最后,让我们从初始列表构造中去掉Linq。请注意,因为这是linq到实体而不是linq到对象,所以我们将数据库中的工作转移到内存中,所以这一位是一个主要的性能杀手。实际上,最好将其替换为对过程的调用,该过程执行中的正在执行的操作,但现在我们开始:
var oldObj = new List<SubTopic>();
foreach(var t in db.SubTopics.AsNoTracking())
if(t => t.TopicId == id)
oldObj.Add(t);
var newObj = new List<SubTopic>(topic.SubTopics);
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if((db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes)))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
break;
}
}
}
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if(db1 => db1.SubTopicId != subTopic.SubTopicId)
{
db.SubTopics.Add(subTopic);
break;
}
}
}
foreach (var subTopic in oldObj)
{
bool allMatch = true;
foreach(var db1 in newObj)
{
if(subTopic.SubTopicId != db1.SubTopicId)
{
allMatch = false;
break;
}
}
if(allMatch)
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
对于如何将某些东西分解成方法,以及如何使用临时方法,人们有一定程度的兴趣,但我认为上面的内容,如果比原始内容更简单的话,更具可读性
删除
oldObj
和newObj
上的ToList()
并将使用IEnumerable
的方法更改为使用IQueryable
。这也可能不是因为同一组被多次击中,所以它不像在许多类似的情况下那样是一个不需要动脑筋的问题,但它确实值得一看。好的。让我们先通过去除任何积垢来简化您所拥有的。您有一些.ToList()
调用只使用过一次的集合,因此它们只是额外的代码,除了浪费时间和内存外什么也不做。让我们把它们排除在干扰之外:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
var upd = newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes))));
var add = newObj
.Where(wb => oldObj
.All(db1 => db1.SubTopicId != wb.SubTopicId));
var del = oldObj
.Where(db1 => newObj
.All(wb => wb.SubTopicId != db1.SubTopicId));
foreach (var subTopic in upd)
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
foreach (var subTopic in add)
{
db.SubTopics.Add(subTopic);
}
foreach (var subTopic in del)
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
现在,让我们将它们移动到foreach
的主体中:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj
.Where(wb => oldObj
.Any(db1 => (db1.SubTopicId == wb.SubTopicId) &&
(db1.Number != wb.Number || !db1.Name.Equals(wb.Name)
|| !db1.Notes.Equals(wb.Notes)))))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
foreach (var subTopic in newObj
.Where(wb => oldObj
.All(db1 => db1.SubTopicId != wb.SubTopicId)))
{
db.SubTopics.Add(subTopic);
}
foreach (var subTopic in oldObj
.Where(db1 => newObj
.All(wb => wb.SubTopicId != db1.SubTopicId)))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
现在让我们将.Where()
作为foreach
逻辑的一部分:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj)
{
if(oldObj.Any(db1 => (db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes))))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
}
}
foreach (var subTopic in newObj)
{
if(oldObj.All(db1 => db1.SubTopicId != subTopic.SubTopicId))
{
db.SubTopics.Add(subTopic);
}
}
foreach (var subTopic in oldObj)
{
if(newObj.All(subTopic.SubTopicId != db1.SubTopicId))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
现在让我们将.Any()
实现为一个循环:
var oldObj = db.SubTopics
.Where(t => t.TopicId == id)
.AsNoTracking()
.ToList();
var newObj = topic.SubTopics.ToList();
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if((db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes)))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
break;
}
}
}
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if(db1 => db1.SubTopicId != subTopic.SubTopicId)
{
db.SubTopics.Add(subTopic);
break;
}
}
}
foreach (var subTopic in oldObj)
{
if(newObj.All(subTopic.SubTopicId != db1.SubTopicId)))
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
现在,让我们对All()
执行相同的操作:
最后,让我们从初始列表构造中去掉Linq。请注意,因为这是linq到实体而不是linq到对象,所以我们将数据库中的工作转移到内存中,所以这一位是一个主要的性能杀手。实际上,最好将其替换为对过程的调用,该过程执行中的正在执行的操作,但现在我们开始:
var oldObj = new List<SubTopic>();
foreach(var t in db.SubTopics.AsNoTracking())
if(t => t.TopicId == id)
oldObj.Add(t);
var newObj = new List<SubTopic>(topic.SubTopics);
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if((db1.SubTopicId == subTopic.SubTopicId) &&
(db1.Number != subTopic.Number || !db1.Name.Equals(subTopic.Name)
|| !db1.Notes.Equals(subTopic.Notes)))
{
db.SubTopics.Attach(subTopic);
db.Entry(subTopic).State = EntityState.Modified;
break;
}
}
}
foreach (var subTopic in newObj)
{
foreach(var db1 in oldObj)
{
if(db1 => db1.SubTopicId != subTopic.SubTopicId)
{
db.SubTopics.Add(subTopic);
break;
}
}
}
foreach (var subTopic in oldObj)
{
bool allMatch = true;
foreach(var db1 in newObj)
{
if(subTopic.SubTopicId != db1.SubTopicId)
{
allMatch = false;
break;
}
}
if(allMatch)
{
db.SubTopics.Attach(subTopic);
db.SubTopics.Remove(subTopic);
}
}
对于如何将某些东西分解成方法,以及如何使用临时方法,人们有一定程度的兴趣,但我认为上面的内容,如果比原始内容更简单的话,更具可读性
删除oldObj
和newObj
上的ToList()
并将使用IEnumerable
的方法更改为使用iQuery>可能是个好主意<