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: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)
/// <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