/// <summary> /// Base implementation to save an instance hierarchy. /// </summary> /// <param name="uow">An open unit of work</param> /// <param name="productInstance">The instance to save</param> /// <returns>The instance entity.</returns> private ProductInstanceEntity SaveInstance(IUnitOfWork uow, ProductInstance productInstance) { // Check if this type is persisted var strategy = InstanceStrategies[productInstance.GetType().Name]; if (strategy.SkipInstances) { return(null); } // Save to entity var archived = uow.GetEntity <ProductInstanceEntity>(productInstance); archived.ProductId = productInstance.Type.Id; strategy.SaveInstance(productInstance, archived); // Save its parts if the have a dedicated archive var partsContainer = ReflectionTool.GetReferences <ProductInstance>(productInstance); foreach (var partGroup in partsContainer) { foreach (var part in partGroup) { var partEntity = SaveInstance(uow, part); if (partEntity == null) // Parts are null when they are skipped { continue; } partEntity.Parent = archived; partEntity.PartLinkId = part.PartLink.Id; } } return(archived); }
/// <summary> /// Recursive function to transform entities into objects /// </summary> private void TransformInstance(IUnitOfWork uow, ProductInstanceEntity entity, ProductInstance productInstance) { // Transform the instance if it has a dedicated storage var product = productInstance.Type; // Check if instances of this type are persisted var strategy = InstanceStrategies[productInstance.GetType().Name]; if (strategy.SkipInstances) { return; } // Transfrom entity to instance strategy.LoadInstance(entity, productInstance); // Group all parts of the instance by the property they belong to var partLinks = ReflectionTool.GetReferences <IProductPartLink>(product) .SelectMany(g => g).ToList(); var partGroups = ReflectionTool.GetReferences <ProductInstance>(productInstance) .ToDictionary(p => p.Key, p => p.ToList()); var partEntityGroups = entity.Parts.GroupBy(p => p.PartLink.PropertyName) .ToDictionary(p => p.Key, p => p.ToList()); // Load and populate parts foreach (var partGroup in partGroups) { var linkStrategy = LinkStrategies[product.GetType().Name][partGroup.Key.Name]; if (linkStrategy.PartCreation == PartSourceStrategy.FromPartlink && partEntityGroups.ContainsKey(partGroup.Key.Name)) { // Update all parts that are also present as entities foreach (var partEntity in partEntityGroups[partGroup.Key.Name]) { var part = partGroup.Value.First(p => p.PartLink.Id == partEntity.PartLinkId); TransformInstance(uow, partEntity, part); } } else if (linkStrategy.PartCreation == PartSourceStrategy.FromEntities) { // Load part using the entity and assign PartLink afterwards var partCollection = partEntityGroups[partGroup.Key.Name].ToList(); var partArticles = TransformArticles(uow, partCollection); for (var index = 0; index < partArticles.Length; index++) { partArticles[index].PartLink = partLinks.Find(pl => pl?.Id == partCollection[index].PartLinkId.Value); } if (typeof(ProductInstance).IsAssignableFrom(partGroup.Key.PropertyType) && partArticles.Length == 0) { partGroup.Key.SetValue(productInstance, partArticles[0]); } else { var elementType = partGroup.Key.PropertyType.GetGenericArguments()[0]; var listType = typeof(List <>).MakeGenericType(elementType); var list = (IList)Activator.CreateInstance(listType); foreach (var partArticle in partArticles) { list.Add(partArticle); } } } } }