C# 比较两个列表对象的最快方法

C# 比较两个列表对象的最快方法,c#,C#,我允许用户将一些数据下载到csv。然后,他们可以编辑一些列,然后上传回来。我需要一种快速高效的方法来比较相似对象之间的某些列,以查看发生了什么变化 目前,我从数据库中提取原始数据,并将其列为一个列表,以便将其全部存储在内存中。大约有10万件物品,所以没那么糟糕。那部分不到一秒钟。然后我加载csv文件并将其放入列表。两个列表具有相同的类类型 然后我在csv数据上循环(因为他们可能删除了一些没有更改但仍可能更改了很多行的行)。对于csv列表中的每一行,我查询来自DB的列表以查找该对象。现在我将csv

我允许用户将一些数据下载到csv。然后,他们可以编辑一些列,然后上传回来。我需要一种快速高效的方法来比较相似对象之间的某些列,以查看发生了什么变化

目前,我从数据库中提取原始数据,并将其列为一个列表,以便将其全部存储在内存中。大约有10万件物品,所以没那么糟糕。那部分不到一秒钟。然后我加载csv文件并将其放入列表。两个列表具有相同的类类型

然后我在csv数据上循环(因为他们可能删除了一些没有更改但仍可能更改了很多行的行)。对于csv列表中的每一行,我查询来自DB的列表以查找该对象。现在我将csv对象和数据库中的对象作为相同的结构。然后,我通过一个自定义的对象比较函数运行它,该函数查看某些列,以查看是否有任何更改

如果发生了变化,我必须通过查询该列的另一个引用列表来验证他们输入的值是否有效。如果无效,我会把它写在例外列表中。最后,如果没有异常,我将保存到db。如果有异常,我不会保存任何内容,并向他们显示错误列表

详细信息比较提供了列列表以及更改的新旧值。我需要它来查询引用列表,以确保在进行更改之前新值有效。这是相当低效的,但它为用户提供了非常详细的信息,说明了上传可能存在的问题,这是非常有价值的

这很慢。我正在寻找加快速度的方法,同时仍然能够向用户提供有关它可能失败原因的详细信息,以便他们能够纠正它

// get all the new records from the csv
            var newData = csv.GetRecords<MyTable>().ToArray();

            // select all data from database to list
            var origData = ctx.MyTable.Select(s => s).ToList();

            // look for any changes in the new data and update the database. note we are looping over the new data so if they removed some data from the csv file it just won't loop over those and they won't change
            foreach (var d in newData)
            {
                // find data so we can compare between new (csv) and current (from db) to see what possibly changed
                var oData = (from o in origData
                             where o.id == d.id
                             select o).FirstOrDefault();

                // only the columns in the updatableColumns list are compared
                var diff = d.DetailedCompare(oData, comparableColumns.ToList());
                if (diff.Count > 0)
                {
                    // even though there are differences between the csv record and db record doesn't mean what the user input is valid. only existing ref data is valid and needs to be checked before a change is made
                    bool changed = false;

                    // make a copy of this original data and we'll check after if we actually were able to make a change to it (was the value provided valid)
                    var data = CopyRecord(oData);

                    // update this record's data fields that have changed with the new data
                    foreach (var v in diff)
                    {
                        // special check for setting a value to NULL as its always valid to do this but wouldn't show up in ref data to pass the next check below
                        if (v.valA == null)
                        {
                            oData.GetType().GetProperty(v.Prop).SetValue(oData, v.valA);
                            oData.UpdatedBy = user;
                            oData.UpdatedDate = DateTime.Now;
                            changed = true;
                        }
                        // validate that the value for this column is in the ref table before allowing an update. note exception if not so we can tell the user
                        else if (refData[v.Prop].Where(a => a.value == v.valA.ToString()).FirstOrDefault() != null)
                        {
                            // update the current objects values with the new objects value as it changed and is a valid value based on the ref data defined for that column
                            oData.GetType().GetProperty(v.Prop).SetValue(oData, v.valA);
                            oData.UpdatedBy = user;
                            oData.UpdatedDate = DateTime.Now;
                            changed = true;
                        }
                        else
                        {
                            // the value provided isn't valid for this column so note this to tell the user
                            exceptions.Add(string.Format("Error: ID: {0}, Value: '{1}' is not valid for column [{2}]. Add the reference data if needed and re-import.", d.id, v.valA, v.Prop));
                        }
                    }

                    // we only need to reattach and save off changes IF we actually changed something to a valid ref value and we had no exceptions for this record
                    if (changed && exceptions.Count == 0)
                    {
                        // because our current object was in memory we will reattached it to EF so we can mark it as changed and SaveChanges() will write it back to the DB
                        ctx.MyTable.Attach(oData);
                        ctx.Entry(oData).State = EntityState.Modified;

                        // add a history record for the change to this product
                        CreateHistoryRecord(data, user);
                    }
                }
            }

            // wait until the very end before making DB changed. we don't save anything if there are exceptions or nothing changed
            if (exceptions.Count == 0)
            {
                ctx.SaveChanges();
            }
//从csv获取所有新记录
var newData=csv.GetRecords().ToArray();
//选择要列出的数据库中的所有数据
var origData=ctx.MyTable.Select(s=>s.ToList();
//查找新数据中的任何更改并更新数据库。请注意,我们正在循环新数据,因此如果他们从csv文件中删除了一些数据,则不会循环这些数据,也不会更改
foreach(newData中的变量d)
{
//查找数据,以便我们可以比较新的(csv)和当前的(来自db)以查看可能发生的变化
变量oData=(从原始数据中的o开始)
其中o.id==d.id
选择o.FirstOrDefault();
//只比较UpdateColumns列表中的列
var diff=d.DetailedCompare(oData,comparableColumns.ToList());
如果(差异计数>0)
{
//尽管csv记录和db记录之间存在差异,但这并不意味着用户输入的内容是有效的。只有现有的ref数据是有效的,需要在进行更改之前进行检查
bool-changed=false;
//制作此原始数据的副本,然后我们将检查是否能够对其进行更改(提供的值是否有效)
var数据=复制记录(oData);
//使用新数据更新已更改的此记录的数据字段
foreach(var v在差异中)
{
//将值设置为NULL的特殊检查,因为这样做总是有效的,但不会显示在ref数据中以通过下面的下一个检查
如果(v.valA==null)
{
oData.GetType().GetProperty(v.Prop).SetValue(oData,v.valA);
oData.UpdatedBy=用户;
oData.updateDate=DateTime.Now;
更改=正确;
}
//在允许更新之前,请验证此列的值是否在ref表中。如果不是,请注意异常,以便我们可以告诉用户
else if(refData[v.Prop].Where(a=>a.value==v.valA.ToString()).FirstOrDefault()!=null)
{
//使用更改后的新对象值更新当前对象值,该值是基于为该列定义的ref数据的有效值
oData.GetType().GetProperty(v.Prop).SetValue(oData,v.valA);
oData.UpdatedBy=用户;
oData.updateDate=DateTime.Now;
更改=正确;
}
其他的
{
//提供的值对此列无效,因此请注意这一点以告知用户
exceptions.Add(string.Format(“错误:ID:{0},值:{1}对列[{2}]无效”)。如果需要,添加引用数据并重新导入。“,d.ID,v.valA,v.Prop”);
}
}
//我们只需要重新连接并保存更改,如果我们实际将某些内容更改为有效的ref值,并且此记录没有异常
if(已更改&&exceptions.Count==0)
{
//因为当前对象在内存中,所以我们将它重新附加到EF,这样我们就可以将它标记为已更改,SaveChanges()将把它写回数据库
ctx.MyTable.Attach(oData);
ctx.Entry(oData).State=EntityState.Modified;
//添加此产品更改的历史记录
CreateHistoryRecord(数据、用户);
}
}
}
//直到最后才更改数据库。如果有异常或没有更改,我们不会保存任何内容
if(exceptions.Count==0)
{
ctx.SaveChanges();
}
第一个大wi