【问题标题】:c# how to retain old value in list after running update queryc#如何在运行更新查询后保留列表中的旧值
【发布时间】:2021-05-18 09:26:25
【问题描述】:

网络核心应用程序。我想出了以下问题。我正在尝试更新 db 表中的值。

 public async Task<MyResponseModel> Update(RequestModel request)
{
  IEnumerable<MyModel> mymodel = await _myRepository.GetAsync(x => Ids.Contains(x.Id));
  List<MyModel> copy = new List<MyModel>();
  copy.AddRange(mymodel)

for (int i = 0; i < mymodel.Count; i++)
{
//some property update
}
myRepository.UpdateRange(mymodel);
await _unitOfWork.CompleteAsync().ConfigureAwait(false);

这里的问题是在复制变量中的上述代码中,我想保留从第一个查询直接返回的旧值。但问题是在执行更新命令后,即使我的复制变量值也会被更新的新值更新。我想将旧值保留在更新前的副本列表中。有人可以帮我找到它的根本原因。任何帮助,将不胜感激。谢谢

【问题讨论】:

    标签: c# .net list asp.net-core


    【解决方案1】:

    快速解决方法获取模型的两个副本:

    public async Task<MyResponseModel> Update(RequestModel request)
    {
        var models = await _myRepository.GetAsync(x => Ids.Contains(x.Id));
        var copyModels = await _myRepository.GetAsync(x => Ids.Contains(x.Id));
    
        foreach (var model in models)
        {
            model.SomeProperty = "new value";
        }
    
        myRepository.UpdateRange(models);
        await _unitOfWork.CompleteAsync().ConfigureAwait(false);
    
        // copyModels still have old previous value
    }
    

    原始问题的根本原因是向新列表添加实例不会创建对象的副本,而是会创建对同一对象的引用的副本。

    【讨论】:

    • 这会在数据库中重复两次查询,这取决于查询可能会很昂贵。最好只查询一次并克隆结果对象。
    • 另外,考虑到一些 ORM 有缓存,为了响应重复的查询,不查询数据库而是返回缓存的响应,即相同的对象,再次复制原始问题。这取决于存储库的特定实现。
    • @Alejandro 这是基于 OP 提供的信息的快速简单的方法 - 这不足以提出更有效的建议。其他一切都是猜测。
    • @Alejandro - 关于 ORM 为第二次查询返回相同的对象 - 你是说如果我在 foreach 循环之后但在调用 CompleteAsync 之前再次调用获取 copyModels 将有更新的属性?
    • 有可能,是的。一些 ORM(例如 NHibernate)会检测到相同的查询运行了两次,然后简单地再次返回相同的对象,有时甚至不查询数据库。如果是这种情况,您最终会遇到与 OP 相同的情况,因为这将是两个包含相同实例的列表。当然,真正发生这种情况取决于存储库的具体实现。
    【解决方案2】:

    您可能想要使用 Extensions 方法:我在 another question 中从用户 ajm 找到了这个答案。

       static class Extensions
    {
        public static IList<T> Clone<T>(this IList<T> listToClone) where T: ICloneable
        {
            return listToClone.Select(item => (T)item.Clone()).ToList();
        }
    }
    

    【讨论】:

      【解决方案3】:

      copy.AddRange(mymodel) 此代码将对 mymodel 进行浅拷贝,因此“copy”变量将指向与“mymodel”变量相同的内存位置中的数据。 要解决此问题,解决方法是在代码行上方更新以下代码 copy.AddRange(JsonConvert.DeserializeObject(JsonConvert.SerializeObject(mymodel))) 这也可以使用反射来完成,但上面是解决方法。

          public async Task<MyResponseModel> Update(RequestModel request)
          {
              IEnumerable<MyModel> mymodel = await _myRepository.GetAsync(x => Ids.Contains(x.Id));
              List<MyModel> copy = new List<MyModel>();
      
              copy.AddRange(JsonConvert.DeserializeObject<List<MyModel>>(JsonConvert.SerializeObject(mymodel)))
      
              for (int i = 0; i < mymodel.Count; i++)
              {
                  //some property update
              }
              myRepository.UpdateRange(mymodel);
              await _unitOfWork.CompleteAsync().ConfigureAwait(false);
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-06
        • 2014-11-16
        • 2019-07-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多