Custom taxonomies installation bug (+ solution)
Hi
This post is for Telerik developers to take care about the bug in future releases, and also I am providing workaround for developers.
BUG: in custom module when you add your own Taxonomies + standard Categories and Tags taxonomies your taxonomies are created but MetaFields are not added to your Content item class
This bug is also presented in Products module from SDK:
EXPECTED BEHAVIOR: Color property value should be saved to ProductItem entity
ACTUAL BEHAVIOR: Color property value isn't saved to ProductItem entity
Following exception is put into website log duting module installation process:
----------------------------------------Timestamp: 05.07.2011 15:58:17Message: HandlingInstanceID: 0efae780-07b1-400f-89b5-f6247094b8d2An exception of type 'Telerik.OpenAccess.Exceptions.DuplicateKeyException' occurred and was caught.---------------------------------------------------------------------------------------------------07/05/2011 22:58:17Type : Telerik.OpenAccess.Exceptions.DuplicateKeyException, Telerik.OpenAccess, Version=2011.1.510.1, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342Message : Insert of '645785618-8d43b71d-1d96-4aa9-be0f-380740b346be' failed: Telerik.OpenAccess.RT.sql.SQLException: Cannot insert duplicate key row in object 'dbo.sf_meta_types' with unique index 'idx_sf_meta_types'.The statement has been terminated. at Telerik.OpenAccess.RT.Adonet2Generic.Impl.PreparedStatementImp.execute() at OpenAccessRuntime.Relational.conn.PooledPreparedStatement.execute() at OpenAccessRuntime.Relational.RelationalStorageManager.generateInserts(NewObjectOID oid, Int32 index, ClassMetaData cmd, PersistGraph graph, Int32[] fieldNos, CharBuf s, Object[] oidData, IntArray toUpdateIndexes)INSERT INTO [sf_meta_types] ([id], [app_name], [assembly_name], [base_class_name], [class_name], [database_inheritance], [is_dynamic], [last_modified], [module_name], [name_space], [section_captions_resource_type], [voa_version]) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)(set event logging to all to see parameter values)Source : Unity_ILEmit_DynamicClassesHelp link : InnerExceptions : System.Exception[]FailedObject : NewObjectOID@3 class=MetaType id=1 realOID=BackendError : Telerik.OpenAccess.RT.sql.SQLException: Cannot insert duplicate key row in object 'dbo.sf_meta_types' with unique index 'idx_sf_meta_types'.The statement has been terminated. at Telerik.OpenAccess.RT.Adonet2Generic.Impl.PreparedStatementImp.execute() at OpenAccessRuntime.Relational.conn.PooledPreparedStatement.execute() at OpenAccessRuntime.Relational.RelationalStorageManager.generateInserts(NewObjectOID oid, Int32 index, ClassMetaData cmd, PersistGraph graph, Int32[] fieldNos, CharBuf s, Object[] oidData, IntArray toUpdateIndexes)Reason : DuplicateKeyCanRetry : FalseData : System.Collections.ListDictionaryInternalTargetSite : Void CommitTransaction()Stack Trace : at DynamicModule.ns.Wrapped_OpenAccessMetaDataProvider_cee42e39aab943f7b28bfa2d226d87c5.CommitTransaction() at Telerik.Sitefinity.Data.ManagerBase`1.SaveChanges() at Telerik.Sitefinity.Services.InstallContext.SaveChanges(Boolean clean) at Telerik.Sitefinity.Services.SystemManager.InitializeModule(ModuleSettings settings, InstallContext installContext, Boolean start)Additional Info:MachineName : THINKPADTimeStamp : 05.07.2011 15:58:17FullName : Telerik.Sitefinity.Utilities, Version=4.1.1395.0, Culture=neutral, PublicKeyToken=b28c218413bdf563AppDomainName : 911f9b7b-1-129543550855244266ThreadIdentity : WindowsIdentity : Thinkpad\AlexRequested URL : /default.aspx? Inner Exception --------------- Type : Telerik.OpenAccess.RT.sql.SQLException, Telerik.OpenAccess.Runtime, Version=2011.1.510.1, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342 Message : Cannot insert duplicate key row in object 'dbo.sf_meta_types' with unique index 'idx_sf_meta_types'.The statement has been terminated. Source : Telerik.OpenAccess.Adonet2 Help link : ErrorCode : 2601 Number : 2601 ObjectId : Description : SQLState=;Cannot insert duplicate key row in object 'dbo.sf_meta_types' with unique index 'idx_sf_meta_types'.The statement has been terminated. Data : System.Collections.ListDictionaryInternal TargetSite : Boolean execute() Stack Trace : at Telerik.OpenAccess.RT.Adonet2Generic.Impl.PreparedStatementImp.execute() at OpenAccessRuntime.Relational.conn.PooledPreparedStatement.execute() at OpenAccessRuntime.Relational.RelationalStorageManager.generateInserts(NewObjectOID oid, Int32 index, ClassMetaData cmd, PersistGraph graph, Int32[] fieldNos, CharBuf s, Object[] oidData, IntArray toUpdateIndexes)/// <summary> /// Installs the taxonomies. /// </summary> /// <param name="initializer">The initializer.</param> protected void InstallCustomTaxonomies(SiteInitializer initializer) //installs the default Tags and Category taxonomies this.InstallTaxonomy(initializer, typeof(ProductItem)); var metaMan = initializer.Context.MetadataManager; var taxMan = initializer.TaxonomyManager; var flatTaxonomy = this.CreateTaxonomy<FlatTaxonomy>(initializer, "Colors", ColorsTaxonomyId, "Color"); var taxon1 = initializer.TaxonomyManager.CreateTaxon<FlatTaxon>(); taxon1.Title = "Red"; taxon1.Name = "Red"; var taxon2 = initializer.TaxonomyManager.CreateTaxon<FlatTaxon>(); taxon2.Title = "Blue"; taxon2.Name = "Blue"; flatTaxonomy.Taxa.Add(taxon1); flatTaxonomy.Taxa.Add(taxon2); var type = metaMan.GetMetaType(typeof(ProductItem)); if (type == null) type = metaMan.CreateMetaType(typeof(ProductItem)); if (!type.Fields.ToList().Any(fld => fld.FieldName == "Colors")) var field = metaMan.CreateMetafield("Colors"); field.TaxonomyProvider = taxMan.Provider.Name; field.TaxonomyId = ColorsTaxonomyId; field.IsSingleTaxon = false; type.Fields.Add(field); var type = metaMan.GetMetaType(typeof(ProductItem)); if (type == null) type = metaMan.CreateMetaType(typeof(ProductItem)); protected void InstallTaxonomy(SiteInitializer initializer, Type itemType, MetaType metaType);protected void InstallTaxonomy(SiteInitializer initializer, Type itemType, MetaType metaType);/// <summary> /// Installs the taxonomies. /// </summary> /// <param name="initializer">The initializer.</param> protected void InstallCustomTaxonomies(SiteInitializer initializer) var metaMan = initializer.Context.MetadataManager; var type = metaMan.GetMetaType(typeof(ProductItem)); if (type == null) type = metaMan.CreateMetaType(typeof(ProductItem)); //installs the default Tags and Category taxonomies this.InstallTaxonomy(initializer, typeof(ProductItem), type); var taxMan = initializer.TaxonomyManager; var flatTaxonomy = this.CreateTaxonomy<FlatTaxonomy>(initializer, "Colors", ColorsTaxonomyId, "Color"); var taxon1 = initializer.TaxonomyManager.CreateTaxon<FlatTaxon>(); taxon1.Title = "Red"; taxon1.Name = "Red"; var taxon2 = initializer.TaxonomyManager.CreateTaxon<FlatTaxon>(); taxon2.Title = "Blue"; taxon2.Name = "Blue"; flatTaxonomy.Taxa.Add(taxon1); flatTaxonomy.Taxa.Add(taxon2); if (!type.Fields.ToList().Any(fld => fld.FieldName == "Colors")) var field = metaMan.CreateMetafield("Colors"); field.TaxonomyProvider = taxMan.Provider.Name; field.TaxonomyId = ColorsTaxonomyId; field.IsSingleTaxon = false; type.Fields.Add(field); Hello Kronos,
An issue like the one you report is not observed in the recently released Sitefinity SP2 and in the latest service pack that goes with it. Still your solution seems to be valid for older releases of Sitefinity. We actually have a fix in the metadataprovider that returns not only metatypes existing in the database but also metatypes that were added but not committed, so the old code should be working ok with the latest version of Sitefinity.
Kind regards,
Nikolay Datchev
the Telerik team