【发布时间】:2018-05-25 06:54:18
【问题描述】:
当我尝试克隆 Product-object 并将克隆保存到数据库时,原始对象会丢失其所有关系数据,例如 ProductPropertyOptionForProducts、IdentifierForProducts 和 InCategories。
这是产品型号:
public class Product
{
public int Id { get; set; }
public int ProductGroupId { get; set; }
public int ProductGroupSortOrder { get; set; }
[Required, MaxLength(30), MinLength(4)] public string Title { get; set; }
[MaxLength(200)] public string Info { get; set; }
[MaxLength(4000)] public string LongInfo { get; set; }
[Required, DataType(DataType.Currency)] public decimal Price { get; set; }
public int Weight { get; set; }
public int ProductTypeId { get; set; }
public ICollection<ProductImage> Images { get; set; }
// Selected property options for this product
public ICollection<PropertyOptionForProduct> ProductPropertyOptionForProducts { get; set; }
// A product can have multiple identifiers (EAN, ISBN, product number, etc.)
public ICollection<IdentifierForProduct> IdentifierForProducts { get; set; }
public ProductType Type { get; set; }
public ICollection<FrontPageProduct> InFrontPages { get; set; }
public ICollection<ProductInCategory> InCategories { get; set; }
}
一些相关模型:
public class ProductInCategory
// A linking table for which products belongs to which categories
{
public int Id { get; set; }
public int ProductId { get; set; }
public int ProductCategoryId { get; set; }
public int SortOrder { get; set; }
// Nav.props.:
public Product Product { get; set; }
public ProductCategory ProductCategory { get; set; }
}
public class PropertyOptionForProduct
{
public int Id { get; set; }
public int ProductId { get; set; }
public int ProductPropertyId { get; set; }
public int ProductPropertyOptionId { get; set; }
// Nav.props.
public Product Product { get; set; }
public ProductPropertyOption ProductPropertyOption { get; set; }
}
public class IdentifierForProduct
{
public int Id { get; set; }
public int ProductId { get; set; }
public int ProductIdentifierId { get; set; }
[StringLength(30), MaxLength(30)]
public string Value { get; set; }
public ProductIdentifier ProductIdentifier { get; set; }
public Product Product { get; set; }
}
原件是这样加载的:
public async Task<Product> GetProduct(int Id)
{
Product DbM = await _context.Products
.Include(ic => ic.InCategories)
.ThenInclude(pc => pc.ProductCategory)
.Include(t => t.Type)
.ThenInclude(iit => iit.Identifiers) //ProductIdentifiersInTypes
.ThenInclude(i => i.Identifier) // ProductIdentifiers
.ThenInclude(ifp => ifp.ProductIdentifiers) // IdentifiersForProducts
.Include(t => t.Type)
.ThenInclude(pit => pit.Properties) // ProductPropertiesInTypes
.ThenInclude(p => p.Property) // ProductProperties
.ThenInclude(po => po.Options) // ProductPropertyOptions
.Include(p => p.ProductPropertyOptionForProducts)
.Where(p => p.Id == Id)
.SingleOrDefaultAsync();
return DbM;
}
这是克隆方法:
private async Task<Product> MakeClone(Product Original)
{
Product Clone = new Product
{
ProductGroupId = Original.ProductGroupId,
ProductGroupSortOrder = Original.ProductGroupSortOrder + 1,
IdentifierForProducts = Original.IdentifierForProducts,
Images = Original.Images,
InCategories = Original.InCategories,
Info = Original.Info,
InFrontPages = Original.InFrontPages,
LongInfo = Original.LongInfo,
Price = Original.Price,
ProductPropertyOptionForProducts = Original.ProductPropertyOptionForProducts,
ProductTypeId = Original.ProductTypeId,
Title = Original.Title,
Type = Original.Type,
Weight = Original.Weight
};
_context.Add(Clone);
await _context.SaveChangesAsync();
return Clone; // and go to the Edit-view.
}
现在,克隆具有原始产品的所有属性,但原始产品的所有关系数据已被剥离。在数据库中,看起来克隆的关系数据已经替换了原来的关系数据。
更新
根据 Georg 的回答,我将 MakeClone()-method 更改为:
private Product MakeClone(Product Original)
{
List<IdentifierForProduct> identifiers = Original
.IdentifierForProducts
.Select(i => CloneIdentifierForProduct(i))
.ToList();
List<PropertyOptionForProduct> propertyOptions = Original
.ProductPropertyOptionForProducts
.Select(o => ClonePropertyOptionForProduct(o))
.ToList();
List<ProductInCategory> inCategories = Original
.InCategories
.Select(c => CloneProductInCategory(c))
.ToList();
List<FrontPageProduct> inFrontPages = Original
.InFrontPages
.Select(f => CloneFrontPageProduct(f))
.ToList();
List<ProductImage> images = Original.Images.Select(i => CloneProductImage(i)).ToList();
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,
Type = Original.Type,
Weight = Original.Weight,
IdentifierForProducts = identifiers,
ProductPropertyOptionForProducts = propertyOptions,
InCategories = inCategories,
InFrontPages = inFrontPages,
Images = images
};
_context.Add(Clone);
// fix FKs
foreach (var ifp in Clone.IdentifierForProducts) ifp.ProductId = Clone.Id;
foreach (var ofp in Clone.ProductPropertyOptionForProducts) ofp.ProductId = Clone.Id;
foreach (var pic in Clone.InCategories) pic.ProductId = Clone.Id;
foreach (var fpp in Clone.InFrontPages) fpp.ProductId = Clone.Id;
foreach (var pi in Clone.Images) pi.ProductId = Clone.Id;
// Lagre klonen i databasen:
_context.SaveChangesAsync();
return Clone;
}
...并添加了用于克隆每个链接数据的单独方法(我认为我不需要显示所有五种方法):
private IdentifierForProduct CloneIdentifierForProduct(IdentifierForProduct ifp)
{
IdentifierForProduct IFP = new IdentifierForProduct
{
Product = ifp.Product,
ProductId = ifp.ProductId,
ProductIdentifier = ifp.ProductIdentifier,
ProductIdentifierId = ifp.ProductIdentifierId,
Value = ifp.Value
};
return IFP;
}
现在我在创建子列表时收到ArgumentNullException。
这可能与例如IdentifierForProduct 也有一个子属性(我也想克隆)这一事实有关吗?
【问题讨论】:
-
InCategories(例如)如何链接到这些对象?该表中是否有外键列? -
克隆对象是一个复杂的过程。例如,这里您没有克隆所有 IEnumerables,而只是将它们的引用复制到新对象中。当您将所有内容传递给实体框架时,我不确定这是否可以
-
能否查看
Original是否有ProductPropertyOptionForProducts等属性?如果不是,那么您必须使用Include(x => x.ProductPropertyOptionForProducts)等等,如果是,则使用AutoMapper克隆复杂对象。在调用MakeClone方法之前,您是如何创建Original的?。 -
@LasseVågsætherKarlsen 查看更新后的问题。我添加了一些链接模型。其余的也遵循相同的模式。
-
IdentifierForProducts在克隆时也应该是new。
标签: c# asp.net-core-mvc entity-framework-core