C# 仅更新不同的更改

C# 仅更新不同的更改,c#,asp.net-mvc,entity-framework,C#,Asp.net Mvc,Entity Framework,我有一个实体集employee\u table,我通过excel表格获取数据,该表格已加载到内存中,用户将单击Save,保存数据库中的更改,第一次插入记录时一切正常,没有问题 但是我如何只更新所做的更改呢?这意味着,假设我有10行和5列,10行中的第7行被修改,5列中的第3列被修改,我只需要更新这些更改并保留其他列的现有值 我可以检查if(myexistingItem.Name!=dbItem.Name){//update},但它非常繁琐且效率低下,我相信有更好的方法来处理 这是我到目前为止得到

我有一个实体集
employee\u table
,我通过excel表格获取数据,该表格已加载到内存中,用户将单击
Save
,保存数据库中的更改,第一次插入记录时一切正常,没有问题

但是我如何只更新所做的更改呢?这意味着,假设我有10行和5列,10行中的第7行被修改,5列中的第3列被修改,我只需要更新这些更改并保留其他列的现有值

我可以检查
if(myexistingItem.Name!=dbItem.Name){//update}
,但它非常繁琐且效率低下,我相信有更好的方法来处理

这是我到目前为止得到的

var excelData = SessionWrapper.GetSession_Model().DataModel.OrderBy(x => x.LocalName).ToList();;
var dbData = context.employee_master.OrderBy(x => x.localname).ToList();

employee_master = dbEntity = employee_master();

if (dbData.Count > 0)
{
   //update
   foreach (var dbItem in dbData)
   {
      foreach(var xlData in excelData)
      {
         if(dbItem.customer == xlData.Customer)
         {
            dbEntity.customer = xlData.Customer;
         }
         //...do check rest of the props....
         db.Entry(dbEntity).State = EntityState.Modified;
         db.employee_master.Add(dbEntity);
      }
   }

   //save
   db.SaveChanges();
}
else
{
  //insert
}

您可以使用反射使此检查更通用

使用此答案可以按属性名访问

public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetProperty(propName).GetValue(src, null);
}
public static void SetPropertyValue(object obj, string propName, object value)
{
    obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
使用此答案可以按属性名访问

public static object GetPropValue(object src, string propName)
{
    return src.GetType().GetProperty(propName).GetValue(src, null);
}
public static void SetPropertyValue(object obj, string propName, object value)
{
    obj.GetType().GetProperty(propName).SetValue(obj, value, null);
}
这个答案是什么

注意:如果需要排除某些属性,可以通过将属性列表传递给该方法非常简单地实现,并且如果要排除或不排除,可以签入

更新: 我正在更新这个答案,以提供更多的上下文,解释为什么我现在不建议使用基于反射的手动解决方案;我还想澄清的是,一旦你确定这样的解决方案符合要求,它本身就没有错

  • 首先,我从代码中假设这是一项正在进行的工作,因此没有完成。在这种情况下,我觉得代码在完成之前不需要更多的复杂性,基于手动反射的方法更适合您编写、测试、调试和维护

  • 例如,现在您似乎遇到了这样一种情况:从excel中的数据到
    employee\u master
    对象中的数据有一个简单的1:1复制。因此,在这种情况下,反射似乎是一个不需要动脑筋的问题,因为它可以为您节省大量枯燥的手动属性指定

  • 但是,当HR(或使用此应用程序的人)向您返回要求时会发生什么:如果Excel工作表上的字段X为空,则将值“空白”复制到目标字段,除非是星期五,在这种情况下,复制值“N.A”

  • 现在,一个通用的解决方案必须适应定制的业务逻辑,并且可能开始变得繁重。我一直处于这种情况,除非你非常小心,否则从长远来看,它最终往往会变成一团乱麻

  • 我只是想指出这一点,并建议至少看看,因为这已经提供了一个非常行之有效的方法来解决您的问题

就效率而言,之所以提到它们,是因为问题提到了它们,我想指出,与手动键入40多个财产分配的效率低下相比,发布的代码中存在更大的效率低下,或者只更新更改的字段

为什么不重写循环:

foreach (var xlData in excelData)
{
    //find existing record in database data:
    var existing = dbData.FirstOrDefault(d=>d.customer==xlData.Customer);
    if(existing!=null)
    {
        //it already exists in database, update it
        //see below for notes on this.

    }
    else
    {
        //it doesn't exist, create employee_master and insert it to context
        //or perform validation to see if the insert can be done, etc.
    }
    //and commit:
    context.SaveChanges();
}
这使您可以避免初始的
if(dbData.Count>0)
,因为您将始终从excel工作表中插入任何在
dbData
中没有匹配项的行,因此您不需要为第一次插入单独的代码块。 它也比当前循环更有效,因为现在您正在为xlData中的每个对象迭代dbData中的每个对象;这意味着如果你有1000个项目在每个你有一百万次迭代

关于更新过程和总体效率的说明 (注意:我知道这个问题不是直接关于效率的,但是因为您在复制属性的上下文中提到了它,所以我只是想让大家思考一下)

  • 除非您正在构建一个必须对多个实体执行此操作的系统,否则我要提醒您不要通过构建基于反射的属性复制器来增加代码的复杂性
  • 如果您考虑要复制的属性数量(即代码< Fo.x= bar .x/COD>类型语句),然后考虑需要一个鲁棒的、完全测试的和可证明有效的基于反射的属性复印机所需的代码。(即,使用内置缓存,这样您就不必不断地重新反映类型属性,这是一种允许您指定异常的机制,处理边缘情况,无论出于何种未知原因,您发现在某些情况下,对于随机列X,值“null”的处理方式略有不同,等等),您可能会发现前者的工作量实际上要少得多:)
  • 请记住,即使是最快的基于反射的解决方案也总是比老式的
    foo.x=bar.x
    赋值慢
  • <> LI>当然,如果你必须为10个或20个独立的实体做这个操作,考虑一般情况,否则我的建议是,手动编写属性拷贝赋值,得到正确的,然后考虑泛化,或者看,例如:
  • 仅就更新已更改的字段而言,我不确定您是否需要更新。如果该记录存在于数据库中,并且用户刚刚提供了该记录的副本,他们声称该记录是该对象的“正确”版本,那么只需复制他们提供的所有值并将其保存到数据库中即可
  • 我之所以这样说,是因为在所有的可能性中,仅发送4个修改字段(相对于25个或其他任何字段)的效率与数据库本身的实际往返开销相比显得微不足道;如果您能够通过不发送所有列来观察此类操作中有意义的性能提高,我会感到惊讶——当然,除非所有列都是
    NVARCHAR(MAX)
    或其他内容:)

  • 如果并发是一个问题(即,其他用户可能正在修改相同的数据),则包括