Asp.net mvc 4 为什么在Entity Framework 6中,当将域模型复制到另一个域模型时,更改副本的值时原始对象会得到更新?

Asp.net mvc 4 为什么在Entity Framework 6中,当将域模型复制到另一个域模型时,更改副本的值时原始对象会得到更新?,asp.net-mvc-4,entity-framework-6,Asp.net Mvc 4,Entity Framework 6,下面是本例所需的模型 public class OrderDetailPackageVM { public OrderDetail OrderDetail { get; set; } public Package Package { get; set; } } public class Package { public Package() { this.PackageProducts = new List<PackageProduct>

下面是本例所需的模型

public class OrderDetailPackageVM
{
    public OrderDetail OrderDetail { get; set; }
    public Package Package { get; set; }
}

public class Package
{
    public Package()
    {
        this.PackageProducts = new List<PackageProduct>();
    }

    public int PackageId { get; set; }

    public int WebsiteId { get; set; }

    public virtual List<PackageProduct> PackageProducts { get; set; }

}

public class PackageProduct
{
    public int PackageProductId { get; set; }

    public int PackageId { get; set; }

    public virtual Package Package { get; set; }

    public int ProductId { get; set; }

    public virtual Product Product { get; set; }

    public int ProductCategoryId { get; set; } // not a FK but data only

    public virtual ProductCategory ProductCategory { get; set; }
}
在我的手表中,我们看到:

pkgs.Package.PackageProducts.Count = 0;
packages.Package.PackageProducts.Count = 0;
当我期待看到:

pkgs.Package.PackageProducts.Count = 6;
packages.Package.PackageProducts.Count = 0;
那么,当更改应用于副本时,为什么原始对象会更改呢。我不记得早期版本的EF中有这种行为

这方面的工作是什么

我认为使用NoTracking进行选择应该是从EF变更跟踪中“释放”模型中的数据

非常感谢你帮助我理解这种行为

以下是我根据以下反馈解决此问题的方法:

public static T DeepClone<T>(this T source)
    {
        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
    }

不创建新对象。将现有对象放置在新列表中。您需要创建全新的对象并手动复制值。这也称为深度复制或克隆,请参阅

如果omu valueInjector为属性分配属性,则会将对象a的列表分配给对象b的列表。因为它是引用类型,所以实际上是相同的。如果你想拥有新的对象,你必须制作一个深度副本。有关更多信息,请参阅

该行为实际上与从EF视图跟踪更改无关。您可以使用引用类型

一个小样本程序:

using System;
using System.Collections.Generic;

namespace _28637405 {

  class Outer {
    public string MyProperty { get; set; }
  }

  class Program {
    static void Main( string[] args ) {
      var listOne = new List<Outer>();
      for ( int i = 0; i < 10; i++ ) {
        listOne.Add( new Outer { MyProperty = "obj #" + (i + 1) } );
      }
      // first line
      Console.WriteLine( listOne[0].MyProperty );
      var listTwo = new List<Outer>();
      listTwo.AddRange( listOne );
      // second line
      Console.WriteLine( listTwo[0].MyProperty );
      listTwo[0].MyProperty = "Changed";
      // third and fourth line
      Console.WriteLine( listOne[0].MyProperty );
      Console.WriteLine( listTwo[0].MyProperty );
      var listThree = new List<Outer>();
      foreach ( var obj in listOne )
        listThree.Add( new Outer { MyProperty = obj.MyProperty } );
      listThree[0].MyProperty += " again";
      // lines 5,6,7
      Console.WriteLine( listOne[0].MyProperty );
      Console.WriteLine( listTwo[0].MyProperty );
      Console.WriteLine( listThree[0].MyProperty );
    }
  }
}
如果将实现ICloneable,则类Outer将如下所示:

使用方法包括向外部浇铸:


谢谢你的回复。这绝对有道理,让我走上了正确的道路。虽然我没有使用你的解决方案。我将把分数奖励给你。我编辑了这篇文章以反映我使用的方法。我在这里找到了方法:
public static T DeepClone<T>(this T source)
    {
        // Don't serialize a null object, simply return the default for that object
        if (Object.ReferenceEquals(source, null))
        {
            return default(T);
        }

        return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source));
    }
using System;
using System.Collections.Generic;

namespace _28637405 {

  class Outer {
    public string MyProperty { get; set; }
  }

  class Program {
    static void Main( string[] args ) {
      var listOne = new List<Outer>();
      for ( int i = 0; i < 10; i++ ) {
        listOne.Add( new Outer { MyProperty = "obj #" + (i + 1) } );
      }
      // first line
      Console.WriteLine( listOne[0].MyProperty );
      var listTwo = new List<Outer>();
      listTwo.AddRange( listOne );
      // second line
      Console.WriteLine( listTwo[0].MyProperty );
      listTwo[0].MyProperty = "Changed";
      // third and fourth line
      Console.WriteLine( listOne[0].MyProperty );
      Console.WriteLine( listTwo[0].MyProperty );
      var listThree = new List<Outer>();
      foreach ( var obj in listOne )
        listThree.Add( new Outer { MyProperty = obj.MyProperty } );
      listThree[0].MyProperty += " again";
      // lines 5,6,7
      Console.WriteLine( listOne[0].MyProperty );
      Console.WriteLine( listTwo[0].MyProperty );
      Console.WriteLine( listThree[0].MyProperty );
    }
  }
}
obj #1
obj #1
Changed
Changed
Changed
Changed
Changed again
class Outer : ICloneable {
  public string MyProperty { get; set; }

  public object Clone() {
    return new Outer { MyProperty = this.MyProperty };
  }
}
var newObject = existingObject.Clone() as Outer;