Saga mapping generator touches class mappings not related to sagas #959
Description
Describe the bug
Description
The saga persister makes an assumption that it needs to create indexes for all foreign-key relationships in the NHibernate context, because saga data could have sub-tables where the class type does not implement IContainSagaData
.
This is probably a bad assumption now that synchronized storage exists, as a user would need to add their own non-saga classes to the NHibernate context in order to use them from a separate handler outside the saga.
Expected behavior
Saga mapper should leave mappings for non-saga-related classes alone.
Actual behavior
Saga mapper creates indexes for class mappings unrelated to the saga. Best case, this creates unnecessary indexes that the user didn't want. Worst case, under certain conditions (like two classes mapping to the same table) the endpoint can fail to start up because touching the same table twice would result in a duplicate index.
The endpoint can fail to start even if installers are disabled as the NHibernate configuration still has to be compiled in order to use the mappings in an endpoint.
Versions
All supported versions are likely affected.
Steps to reproduce
- Create and run a project using the code from this gist.
- Error is thrown on endpoint startup.
Relevant log output
Unhandled exception. NHibernate.MappingException: Index IDX_9669ABAB already exists!
at NHibernate.Mapping.Table.AddIndex(Index index)
at NServiceBus.SagaPersisters.NHibernate.AutoPersistence.SagaModelMapper.AddMappings(Configuration configuration, SagaMetadataCollection allSagaMetadata, IEnumerable`1 types, Func`2 tableNamingConvention) in /_/src/NServiceBus.NHibernate/SagaPersisters/SagaModelMapper.cs:line 68
at NServiceBus.Features.NHibernateSagaStorage.ApplyMappings(ReadOnlySettings settings, Configuration configuration) in /_/src/NServiceBus.NHibernate/SagaPersisters/NHibernateSagaStorage.cs:line 48
at System.Collections.Generic.List`1.ForEach(Action`1 action)
at NServiceBus.Features.NHibernateStorageSession.Setup(FeatureConfigurationContext context) in /_/src/NServiceBus.NHibernate/SynchronizedStorage/NHibernateStorageSession.cs:line 110
at NServiceBus.Features.FeatureActivator.FeatureInfo.InitializeFrom(FeatureConfigurationContext featureConfigurationContext) in /_/src/NServiceBus.Core/Features/FeatureActivator.cs:line 225
at NServiceBus.Features.FeatureActivator.ActivateFeature(FeatureInfo featureInfo, List`1 featuresToActivate, FeatureConfigurationContext featureConfigurationContext) in /_/src/NServiceBus.Core/Features/FeatureActivator.cs:line 188
at NServiceBus.Features.FeatureActivator.SetupFeatures(FeatureConfigurationContext featureConfigurationContext) in /_/src/NServiceBus.Core/Features/FeatureActivator.cs:line 54
at NServiceBus.EndpointCreator.Initialize() in /_/src/NServiceBus.Core/EndpointCreator.cs:line 59
at NServiceBus.EndpointCreator.Create(SettingsHolder settings, Configuration hostingConfiguration) in /_/src/NServiceBus.Core/EndpointCreator.cs:line 25
at NServiceBus.HostCreator.CreateWithInternallyManagedContainer(EndpointConfiguration endpointConfiguration) in /_/src/NServiceBus.Core/Hosting/HostCreator.cs:line 79
at NServiceBus.Endpoint.Start(EndpointConfiguration configuration) in /_/src/NServiceBus.Core/Endpoint.cs:line 29
at NHibernateRepro.Program.Main(String[] args) in C:\code\NHibernateRepro\Program.cs:line 37
at NHibernateRepro.Program.<Main>(String[] args)
Additional Information
Workarounds
- Don't use synchronized storage, and rely on distributed transactions.
- Segregate sagas into their own endpoints without other NHibernate models.
Possible solutions
Instead of affecting all types, use reflection to create a map of only types
Additional information
None
Activity