Parallel foreach issue while deleting a record
Hi,
Please find below code where I am trying to acheive parallel deleting of all products in sitefinity. Looks like there is a scoping issue.
using (CatalogManager catMgr = CatalogManager.GetManager())
List<Product> products = catMgr.GetProducts().ToList();
Parallel.ForEach(products, product =>
catMgr.DeleteProduct(product);
catMgr.SaveChanges();
);
This code gives the error <b>Object references between two different object scopes are not allowed. The object 'Telerik.Sitefinity.DynamicTypes.Model.sf_ec_prdct_generalproduct' is already managed by 'ObjectScopeImpl 0x38 OpenAccessRuntime.EnlistableObjectScope' and was tried to be managed again by 'ObjectScopeImpl 0xfd OpenAccessRuntime.EnlistableObjectScope'.</b>
Please let me know in case I am missing something.
Thanks
Praneeth
Hi Praneeth,
The error is caused by the fact that the manager did not save changes between two different operations, thus the managers works in different scope, which is not allowed.
More information about deletion of Products could be found here.
Regards,
Svetoslav Manchev
Telerik
Thank you for your reply. Please let me know in case there is any alternative to parallely delete multiple records. I cannot rely on one by one delete as I have approximately 200,000 records and it is taking a very lot of time.
Thanks
Praneeth
Hello Praneeth,
As the parallel items deletion is not allowed, the option for is to get all the Items (Products) in a batches (for example by 500), iterate in a loop and delete them one by one. Than to call manager.SaveChanges() after each batch.
Regards,
Svetoslav Manchev
Telerik
Anything similar to insert multiple users/products/orders. Please note all are new users/products/orders.
This task is for migrating from existing ecomm database to sitefinity database.
Thanks,
Praneeth
Hello Praneeth,
More information and samples about eCommerce API is available in that documentation.
How to manage users programatically is described here.
Regards,
Svetoslav Manchev
Telerik
Hello Svetoslav,
Based on the suggestion I did write the code in batches but it still seem to be slow. I tried batches of 10. Please find my codesnippet below. catalogmanager.SaveChanges() for 10 products takes a long time. Please check and let me know in case I missed anything.
private void DeleteProducts(DynamicModuleManager dynamicModuleManager, DynamicContent content, IEnumerable<ProductImportCSV> products)
try
DynamicContent dynamicItemMaster = dynamicModuleManager.Lifecycle.Edit(content) as DynamicContent;
if (dynamicItemMaster == null)
throw new ApplicationException("DeleteProducts Product Dynamic Item Master was null!");
DynamicContent dynamicItemTemp = dynamicModuleManager.Lifecycle.CheckOut(dynamicItemMaster) as DynamicContent;
if (dynamicItemTemp == null)
throw new ApplicationException("DeleteProducts Product Dynamic Item Temp was null!");
dynamicItemTemp.SetValue(BatchUploadConstants.JobStatus, ProductBatchUploadStatus.Deleting.ToString());
PublishDynamicModule(dynamicModuleManager, dynamicItemTemp);
Guid vendorid = content.GetValue<Guid>(BatchUploadConstants.VendorId);
using (CatalogManager catalogManager = CatalogManager.GetManager())
catalogManager.Provider.SuppressSecurityChecks = true;
IEnumerable<ProductImportCSV> productImportCsvs = products as IList<ProductImportCSV> ?? products.ToList();
// ignore empty records. most likely issue with csv
productImportCsvs = productImportCsvs.Where(p => !string.IsNullOrEmpty(p.SKU));
IQueryable<Product> masterProducts = catalogManager.GetProducts().Where(p => p.Status == ContentLifecycleStatus.Master );
var deleteMasterProducts = Enumerable.Where(masterProducts, p => p.GetValue<TrackedList<Guid>>(DynamicProductConstants.Category).Contains(vendorid));
// Run in batches
int skip = 0;
int take = _batchSize == 0 ? 10 : _batchSize;
int currentCount = 0;
int totalCount = deleteMasterProducts.Count();
while (currentCount < totalCount)
string skusNotDeleted = string.Empty;
try
var chunkedProducts = deleteMasterProducts.Skip(skip).Take(take);
skip = skip + take;
currentCount = skip;
foreach (Product product in chunkedProducts)
if (string.IsNullOrEmpty(product.Sku))
continue;
skusNotDeleted += product.Sku + " ,";
catalogManager.DeleteProduct(product);
catalogManager.Provider.FlushTransaction();
catalogManager.SaveChanges();
GC.Collect();
catch
_errorLog.Append(" SKUs not deleted are : " + skusNotDeleted + ". ");
catch (Exception ex)
_errorLog.Append("Error occurred while deleting and exception message is : " + ex.Message + " " + Environment.NewLine);
Hello Praneeth,
The code seems OK. Furthermore I have test product deletion of 12 products using the following code:
public
static
void
DeleteProducts()
CatalogManager catalogManager = CatalogManager.GetManager();
var products = catalogManager.GetProducts();
foreach
(var product
in
products)
catalogManager.DeleteItem(product,
null
);
catalogManager.SaveChanges();
To delete the records i have used below code.
I have created the records using the dynamic module and wanted to delete all old records so i have write the code like below. may be this code helpful to other
public static void DeleteAllUnclaimedDividendRecords()
DynamicModuleManager dynamicModuleManager = DynamicModuleManager.GetManager();
Type unclaimedDividendType = TypeResolutionService.ResolveType("Telerik.Sitefinity.DynamicTypes.Model.UnclaimedDividend.UnclaimedDividend");
var myCollection = dynamicModuleManager.GetDataItems(unclaimedDividendType);
foreach (var item in myCollection)
dynamicModuleManager.DeleteItem(item);
dynamicModuleManager.SaveChanges();
Thanks,
Murli
Hi Murli,
Thank you for the shared solution with the community.
Regards,
Svetoslav Manchev
Telerik