When upgrading from older Commerce versions, for example R1SP2 or 7.5,the error "The content has to belong to EPiServer.Commerce.Catalog.Provider.CatalogContentProvider" might be experienced. It can be difficult to find the content id causing the issue.
Related forum thread
Her eis a descrption on how to troubleshoot this error, find the erroneous content and then delete the content.
Create an empty cms/commerce front site with the episerver VS extension and connect the site in datanase connectionstrings to copies of the original databases.
Make sure you can access the cms backend.
Create an implementation of CatalogContentStructureProvider and replace the episerver implementation during initialization - see code below.
Set a break point in the function - public override int GetChildEntryCount(CatalogContentBase content) at the appropriate line.
In VS debug and recreate the issue - note the content id in when the exception occurs and the.
Then delete the content using sql using debugging the code and function below
Remember to backup the cms database first
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
public class EpiProfileMigratorBugInitializationModule : IConfigurableModule
{
public void Initialize(InitializationEngine context)
{
}
public void Uninitialize(InitializationEngine context)
{
}
public void ConfigureContainer(ServiceConfigurationContext context)
{
context.Container.Configure(container =>
{
container.For<CatalogContentStructureProvider>().Singleton().Use<MyCatalogContentStructureProvider>();
//.Named(new PageTreeComponent().DefinitionName);
});
}
}
public class MyCatalogContentStructureProvider : CatalogContentStructureProvider
{
private readonly ReferenceConverter _referenceConverter;
private readonly IContentProviderManager _contentProviderManager;
private readonly ISynchronizedObjectInstanceCache _objectInstanceCache;
/// <summary>
/// Initializes a new instance of the <see cref="T:EPiServer.Commerce.Catalog.Provider.CatalogContentStructureProvider" /> class.
/// </summary>
/// <param name="referenceConverter">The reference converter.</param>
/// <param name="contentProviderManager">The content provider manager.</param>
/// <param name="objectInstanceCache">The object instance cache.</param>
public MyCatalogContentStructureProvider(ReferenceConverter referenceConverter, IContentProviderManager contentProviderManager, ISynchronizedObjectInstanceCache objectInstanceCache)
: base(referenceConverter, contentProviderManager, objectInstanceCache)
{
_referenceConverter = referenceConverter;
_contentProviderManager = contentProviderManager;
_objectInstanceCache = objectInstanceCache;
}
/// <summary>
/// Gets the number of child nodes of the catalog content.
/// </summary>
/// <param name="content">The catalog content.</param>
/// <returns>For <see cref="T:EPiServer.Commerce.Catalog.ContentTypes.RootContent" />: The number of catalogs.
/// For <see cref="T:EPiServer.Commerce.Catalog.ContentTypes.CatalogContent" />: The number of nodes directly under the catalog.
/// For <see cref="T:EPiServer.Commerce.Catalog.ContentTypes.NodeContent" />: The number of nodes that reference this node as parent either directly or via a <see cref="T:EPiServer.Commerce.Catalog.Linking.Relation" />,
/// filtered by matching catalogs.
/// For other catalog content: 0.</returns>
/// <exception cref="T:System.ArgumentException">The content has to belong to the catalog content provider.</exception>
public override int GetChildNodeCount(CatalogContentBase content)
{
//Validator.ThrowIfNull(nameof(content), (object)content);
ContentReference contentLink = content.ContentLink;
CatalogContentProvider provider = this._contentProviderManager.ProviderMap.GetProvider(contentLink) as CatalogContentProvider;
if (provider == null)
throw new ArgumentException("The content has to belong to " + typeof(CatalogContentProvider).FullName, nameof(content));
if (contentLink.CompareToIgnoreWorkID(this._referenceConverter.GetRootLink()))
return provider.GetChildrenReferences<CatalogContent>(contentLink, (string)null, -1, -1).Count;
switch (this._referenceConverter.GetContentType(contentLink))
{
case CatalogContentType.Catalog:
return this.GetChildNodeCount(content.CatalogId, 0);
case CatalogContentType.CatalogNode:
return this.GetChildNodeCount(content.CatalogId, this._referenceConverter.GetObjectId(contentLink));
default:
return 0;
}
}
private string nameof(CatalogContentBase content)
{
throw new NotImplementedException();
}
/// <summary>
/// Gets the number of child entries of the catalog content.
/// </summary>
/// <param name="content">The catalog content.</param>
/// <returns>For <see cref="T:EPiServer.Commerce.Catalog.ContentTypes.CatalogContent" />: The number of entries directly under the catalog.
/// For <see cref="T:EPiServer.Commerce.Catalog.ContentTypes.NodeContent" />: The number of entries that reference this node as parent via a <see cref="T:EPiServer.Commerce.Catalog.Linking.Relation" />,
/// filtered by matching catalogs.
/// For other catalog content: 0.</returns>
/// <exception cref="T:System.ArgumentException">The content has to belong to the catalog content provider.</exception>
public override int GetChildEntryCount(CatalogContentBase content)
{
//Validator.ThrowIfNull(nameof(content), (object)content);
ContentReference contentLink = content.ContentLink;
if (!(this._contentProviderManager.ProviderMap.GetProvider(contentLink) is CatalogContentProvider))
throw new ArgumentException("The content has to belong to " + typeof(CatalogContentProvider).FullName, nameof(content));
switch (this._referenceConverter.GetContentType(contentLink))
{
case CatalogContentType.Catalog:
return this.GetChildEntryCount(content.CatalogId, 0);
case CatalogContentType.CatalogNode:
return this.GetChildEntryCount(content.CatalogId, this._referenceConverter.GetObjectId(contentLink));
default:
return 0;
}
}
/// <summary>Gets the child node count through cache.</summary>
/// <param name="catalogId">The catalog id.</param>
/// <param name="parentNodeId">The parent node id.</param>
/// <returns></returns>
protected virtual int GetChildNodeCount(int catalogId, int parentNodeId)
{
Func<IEnumerable<string>> cacheMasterKeys = (Func<IEnumerable<string>>)(() => (IEnumerable<string>)new string[2] { MasterCacheKeys.AnyNodeKey, MasterCacheKeys.AnyNodeRelationKey });
return this.ReadThroughCache("ecf_CatalogNode_ChildNodeCount", catalogId, parentNodeId, "EP:ECF:CNCnt:", cacheMasterKeys);
}
/// <summary>Gets the child entry count through cache.</summary>
/// <param name="catalogId">The catalog id.</param>
/// <param name="parentNodeId">The parent node id.</param>
/// <returns></returns>
protected virtual int GetChildEntryCount(int catalogId, int parentNodeId)
{
Func<IEnumerable<string>> cacheMasterKeys = (Func<IEnumerable<string>>)(() => (IEnumerable<string>)new string[2] { MasterCacheKeys.AnyEntryKey, MasterCacheKeys.AnyNodeRelationKey });
return this.ReadThroughCache("ecf_CatalogNode_ChildEntryCount", catalogId, parentNodeId, "EP:ECF:CECnt:", cacheMasterKeys);
}
private int ReadThroughCache(string storedProcedure, int catalogId, int parentNodeId, string cachePrefix, Func<IEnumerable<string>> cacheMasterKeys)
{
int num;
if (!this._objectInstanceCache.ReadThrough<IDictionary<int, int>>(cachePrefix + (object)catalogId, (Func<IDictionary<int, int>>)(() => this.ReadFromDb(storedProcedure, catalogId)), (Func<IDictionary<int, int>, CacheEvictionPolicy>)(x => new CacheEvictionPolicy((IEnumerable<string>)null, cacheMasterKeys())), ReadStrategy.Wait).TryGetValue(parentNodeId, out num))
num = 0;
return num;
}
private IDictionary<int, int> ReadFromDb(string storedProcedure, int catalogId)
{
DataParameter[] dataParameterArray = new DataParameter[1] { new DataParameter("CatalogId", (object)catalogId, DataParameterType.Int) };
DataTable dataTable = DBHelper.ExecuteDataTable(MetaDataContext.Instance, CommandType.StoredProcedure, storedProcedure, dataParameterArray);
Dictionary<int, int> dictionary = new Dictionary<int, int>();
foreach (DataRow dataRow in dataTable.Select())
{
string index1 = "ParentNodeId";
int int32_1 = Convert.ToInt32(dataRow[index1]);
string index2 = "ChildCount";
int int32_2 = Convert.ToInt32(dataRow[index2]);
dictionary[int32_1] = int32_2;
}
return (IDictionary<int, int>)dictionary;
}
}
SQL to delete content - Remember to backup the cms database first
delete FROM [tblContentlanguage] WHERE [fkContentID]=1234
delete FROM [tblWorkContent] where fkContentID = 1234
delete FROM [tblContentAccess] WHERE [fkContentID]=1234
delete FROM [tblContentProperty] WHERE [fkContentID]=1234
Please sign in to leave a comment.