克隆Product对象并保存至数据库后,原对象丢失关联数据
解决Product克隆后原对象关联数据丢失的问题
嘿,我一眼就看出问题出在哪了——你在克隆Product的时候,直接把原对象的关联集合(比如IdentifierForProducts、InCategories这些)赋值给了克隆对象。Entity Framework的实体跟踪机制会认为这些关联项被“转移”到了新的Product上,所以会把原对象的外键清空,导致原对象失去所有关联数据。
要解决这个问题,你不能直接引用原对象的关联实体,而是要为每个关联项创建全新的实例,让EF把它们当作新的记录插入数据库,而不是转移现有记录的归属。
第一步:编写关联实体的克隆辅助方法
先给每个关联实体写一个克隆方法,复制必要的属性,但不要复制主键(让数据库自动生成),也不要设置Product导航属性(后续EF会通过外键自动关联):
private IdentifierForProduct CloneIdentifierForProduct(IdentifierForProduct original) { return new IdentifierForProduct { ProductIdentifierId = original.ProductIdentifierId, Value = original.Value // 不设置Id和Product属性,交给EF处理 }; } private PropertyOptionForProduct ClonePropertyOptionForProduct(PropertyOptionForProduct original) { return new PropertyOptionForProduct { ProductPropertyId = original.ProductPropertyId, ProductPropertyOptionId = original.ProductPropertyOptionId }; } private ProductInCategory CloneProductInCategory(ProductInCategory original) { return new ProductInCategory { ProductCategoryId = original.ProductCategoryId, SortOrder = original.SortOrder }; } private FrontPageProduct CloneFrontPageProduct(FrontPageProduct original) { // 根据你的FrontPageProduct实际结构调整,复制需要的属性 return new FrontPageProduct { // 比如SortOrder这类属性,不要复制Id和Product }; } private ProductImage CloneProductImage(ProductImage original) { return new ProductImage { // 复制图片的Url、排序值等属性,不复制Id和Product }; }
第二步:修改MakeClone方法
重新编写克隆方法,先创建Product主实体(只复制标量属性和外键),再为它生成全新的关联集合:
private async Task<Product> MakeClone(Product Original) { // 先创建Product主实体,只复制基础属性和外键,不关联导航集合 Product Clone = new Product { ProductGroupId = Original.ProductGroupId, ProductGroupSortOrder = Original.ProductGroupSortOrder + 1, Info = Original.Info, LongInfo = Original.LongInfo, Price = Original.Price, ProductTypeId = Original.ProductTypeId, Title = Original.Title, Weight = Original.Weight // 不要直接赋值Type、Images这些导航属性,只保留外键即可 }; // 为克隆对象生成全新的关联实体集合 Clone.IdentifierForProducts = Original.IdentifierForProducts .Select(i => CloneIdentifierForProduct(i)) .ToList(); Clone.ProductPropertyOptionForProducts = Original.ProductPropertyOptionForProducts .Select(o => ClonePropertyOptionForProduct(o)) .ToList(); Clone.InCategories = Original.InCategories .Select(c => CloneProductInCategory(c)) .ToList(); Clone.InFrontPages = Original.InFrontPages .Select(f => CloneFrontPageProduct(f)) .ToList(); Clone.Images = Original.Images .Select(i => CloneProductImage(i)) .ToList(); _context.Add(Clone); await _context.SaveChangesAsync(); return Clone; }
关键说明
- 每个关联实体都是全新的实例,EF会把它们作为新记录插入数据库,自动将外键指向克隆后的Product,不会影响原对象的关联数据
- 不要复制关联实体的
Id,让数据库自动生成新主键;也不要设置Product导航属性,EF会通过外键自动建立关联 - 对于
Product.Type这类引用实体,我们只需要复制ProductTypeId外键即可,不需要复制整个实体——这是合理的,因为克隆产品本来就属于同一个产品类型
这样修改后,克隆对象会拥有独立的关联数据,原对象的关联数据也不会丢失啦!
内容的提问来源于stack exchange,提问作者Stian
相关产品推荐
相关产品推荐

