I tried with a HashSet<DebtActivities>
and that worked, using ICollection resulted in the following exception:
NHibernate.MappingException: Could not determine type for: System.Collections.Generic.ICollection`1[[DebtActivities, Server.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, for columns: NHibernate.Mapping.Column(Activities)
at NHibernate.Mapping.SimpleValue.get_Type()
at NHibernate.Tuple.PropertyFactory.BuildStandardProperty(Property property, Boolean lazyAvailable)
at NHibernate.Tuple.Component.ComponentMetamodel..ctor(Component component)
at NHibernate.Mapping.Component.BuildType()
at NHibernate.Mapping.Component.get_Type()
at NHibernate.Mapping.SimpleValue.IsValid(IMapping mapping)
at NHibernate.Mapping.Collection.Validate(IMapping mapping)
at NHibernate.Cfg.Configuration.ValidateCollections()
at NHibernate.Cfg.Configuration.Validate()
at NHibernate.Cfg.Configuration.BuildSessionFactory()
at NServiceBus.Features.NHibernateStorageSession.Setup(FeatureConfigurationContext context) in C:\BuildAgent\work\4caed983f8dafcd5\src\NServiceBus.NHibernate\SynchronizedStorage\NHibernateStorageSession.cs:line 58
at NServiceBus.Features.FeatureActivator.ActivateFeature(FeatureInfo featureInfo, List`1 featuresToActivate, IConfigureComponents container, PipelineSettings pipelineSettings, RoutingComponent routing, ReceiveConfiguration receiveConfiguration) in C:\BuildAgent\work\ed946b9f0e4aae01\src\NServiceBus.Core\Features\FeatureActivator.cs:line 193
at NServiceBus.Features.FeatureActivator.SetupFeatures(IConfigureComponents container, PipelineSettings pipelineSettings, RoutingComponent routing, ReceiveConfiguration receiveConfiguration) in C:\BuildAgent\work\ed946b9f0e4aae01\src\NServiceBus.Core\Features\FeatureActivator.cs:line 57
at NServiceBus.InitializableEndpoint.Initialize() in C:\BuildAgent\work\ed946b9f0e4aae01\src\NServiceBus.Core\InitializableEndpoint.cs:line 54
at NServiceBus.Endpoint.Start(EndpointConfiguration configuration) in C:\BuildAgent\work\ed946b9f0e4aae01\src\NServiceBus.Core\Endpoint.cs:line 27
at Program.Main() in S:\particular\docs.particular.net\samples\nhibernate\simple\NHibernate_8\Server\Program.cs:line 35
at Program.<Main>()
Interestingly using ICollection<DebtActivities>
did work on the aggregate root (ProposalsSagaData
).
Looking further in the created schema I see that activities is mapped to a varbinary(max)
which seems to not use a class mapping for the Activities
property but uses binary serialization. This likely because DebtActivityTrack
is not an NHibernate entity due to a missing Id property.
Solutions:
Use a flagged enum
Instead of using an enum you could maybe use a flagged enum and not use a collection. This results in an int column but would require you to use enum operators in code
public class DebtActivityTrack
{
public virtual int DebtIdentifier { get; set; }
public virtual DebtActivities Activities { get; set; }
}
[Flags]
public enum DebtActivities
{
AccountNumberChange = 1,// Notice the values require to be power of 2
BalanceChange = 2,
Reinstated = 4,
Cleared = 8,
PaymentChange = 16,
ContractualPaymentChange = 32,
Transferred = 64,
New = 128
}
Convert DebtActivityTrack to an entity
You could make DebtActivityTrack
an entity by adding an Id
property which I recommend anyway to do as without it every read/write will DELETE/INSERT all collection items. As this now becomes an entity the enum will be mapped to its own table.
public class ProposalsSagaData : ContainSagaData
{
public virtual int ClientReferenceNumber { get; set; }
public virtual IList<DebtActivityTrack> DebtActivities { get; set; } // Potentially this can be an ICollection too, I don't think list order is relevant but would require a custom mapping.
public virtual bool TimeoutRequested { get; set; }
public ProposalsSagaData()
{
DebtActivities = new List<DebtActivityTrack>();
}
}
public class DebtActivityTrack
{
public virtual Guid Id { get; set; } // Added Id property to make it an entity
public virtual int DebtIdentifier { get; set; }
public virtual ICollection<DebtActivities> Activities { get; set; } = new HashSet<DebtActivities>(); // Converted to ICollection/HashSet as I think you would not allow the same enum value to be there more than once.
}
public enum DebtActivities
{
AccountNumberChange = 0,
BalanceChange = 1,
Reinstated = 2,
Cleared = 3,
PaymentChange = 4,
ContractualPaymentChange = 5,
Transferred = 6,
New = 7
}