1-888-365-2779
+1-888-365-2779
Try Now
More in this section

Forums / Bugs & Issues / Custom taxonomies installation bug (+ solution)

Custom taxonomies installation bug (+ solution)

2 posts, 0 answered
  1. Kronos
    Kronos avatar
    17 posts
    Registered:
    08 Apr 2011
    05 Jul 2011
    Link to this post
    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:17
     
    Message: HandlingInstanceID: 0efae780-07b1-400f-89b5-f6247094b8d2
    An exception of type 'Telerik.OpenAccess.Exceptions.DuplicateKeyException' occurred and was caught.
    ---------------------------------------------------------------------------------------------------
    07/05/2011 22:58:17
    Type : Telerik.OpenAccess.Exceptions.DuplicateKeyException, Telerik.OpenAccess, Version=2011.1.510.1, Culture=neutral, PublicKeyToken=7ce17eeaf1d59342
    Message : 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_DynamicClasses
    Help 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 : DuplicateKey
    CanRetry : False
    Data : System.Collections.ListDictionaryInternal
    TargetSite : 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 : THINKPAD
    TimeStamp : 05.07.2011 15:58:17
    FullName : Telerik.Sitefinity.Utilities, Version=4.1.1395.0, Culture=neutral, PublicKeyToken=b28c218413bdf563
    AppDomainName : 911f9b7b-1-129543550855244266
    ThreadIdentity :
    WindowsIdentity : Thinkpad\Alex
    Requested 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)

    Code example that produce bug (taken from Products module):

    /// <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);
                }
     
            }

    I have looked thorough InstallTaxonomy method source code and found the reason of wrong behavior:

    InstallTaxonomy method is working the same way as Colors taxonomy installation in InstallCustomTaxonomies, and also have analogue of following construction:
    var type = metaMan.GetMetaType(typeof(ProductItem));
                if (type == null)
                {
                    type = metaMan.CreateMetaType(typeof(ProductItem));
                }

    So inside the InstallTaxonomy method metaMan.CreateMetaType is executed and new MetaType created, it is necessary if meta type doesn't exist and all seems to be right

    BUT

    when in our code we are executing metaMan.GetMetaType it returns null instead of expected MetaType object created inside standard InstallTaxonomy method. And our code creates the second MetaType, and our MetaField is applied to that second MetaType.

    Then when all operations are commited to DB first MetaType (from InstallTaxonomy) is added and Categories, Tags meta fields applied to it. Second MetaType insertion occure Exception, and our taxonomy meta fields aren't applied of course because they are added to wrong MetaType.

    OFFER FOR FUTURE RELEASES TO FIX THE ISSUE

    Please allow metaMan.GetMetaType return value of added but not commited to DB MetaType

    - or -

    Create MetaType parameter for InstallTaxonomy method:
    protected void InstallTaxonomy(SiteInitializer initializer, Type itemType, MetaType metaType);
    to make developer able to declare MetaType only once

    WORKAROUND

    My workaround is to create method with signature
    protected void InstallTaxonomy(SiteInitializer initializer, Type itemType, MetaType metaType);

    which code is the same as taken from original method using Reflector but without MetaType initialization, and initialize type only once in the beginning of InstallCustomTaxonomies methos:

    /// <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);
                }
     
            }

    Best regards,
    Alex
  2. Nikolay Datchev
    Nikolay Datchev avatar
    87 posts
    Registered:
    01 Nov 2016
    07 Jul 2011
    Link to this post
    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
    Do you want to have your say in the Sitefinity development roadmap? Do you want to know when a feature you requested is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
2 posts, 0 answered