Below are the necessary models for this example.
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; }
}
In the following code snippet, you should see the problem illustrated.
List<OrderDetailPackageVM> pkgs = (from odx in db.OrderDetails
from pax in db.Packages
where odx.OrderId == orderId
&& pax.PackageId == odx.PackageId
&& odx.PricelistProduct.Product.isStandalone == true
&& pax.WebsiteId == websiteId
select new OrderDetailPackageVM
{
Package = pax,
OrderDetail = odx
}).AsNoTracking().ToList();
List<OrderDetailPackageVM> packages = new List<OrderDetailPackageVM>();
packages.AddRange(pkgs);
//also tried packages = pkgs;
//also tried packages.injectFrom(pkgs) //from omu valueInjector - similar to automapper
At this point in my watch we see: pkgs.Package.PackageProducts.Count = 6; packages.Package.PackageProducts.Count = 6;
foreach (OrderDetailPackageVM pac in packages)
{
pac.Package.PackageProducts.RemoveAll();
}
At this point in my watch we see:
pkgs.Package.PackageProducts.Count = 0;
packages.Package.PackageProducts.Count = 0;
When I was expecting to see:
pkgs.Package.PackageProducts.Count = 6;
packages.Package.PackageProducts.Count = 0;
So why is the original object changing when the changes are applied to the copy. I do not remember this behavior in earlier versions of EF?
And what is the work-around for this?
I thought doing a select with NoTracking was supposed to 'Free' the data in the model from EF change tracking?
Thanks so much for helping me understand this behavior.
THE FOLLOWING IS THE METHOD I USED TO SOLVE THIS ISSUE BASED ON FEEDBACK BELOW:
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));
}