Когда я пытаюсь клонировать Product
-объект и сохранить клон в базе данных, исходный объект теряет все свои реляционные данные, такие как 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;
}
Thisэто метод клонирования:
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.
}
Теперь клон обладает всеми свойствами исходного продукта, но в оригинале удалены все его реляционные данные.В базе данных похоже, что реляционные данные клона заменили исходные.
ОБНОВЛЕНИЕ
В соответствии с ответом Георга, я изменил свой MakeClone()
-методк этому:
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
также имеет дочернее свойство (которое я также хочу клонировать)