How to map an IDictionary<string, string> with Fluent NHibernate's class mapping, and test that mapping?
-
04-06-2021 - |
Question
My MassTransit saga has only one field that will not map correctly. It is -
public virtual IDictionary<string, string> Rows
{
get { return _rows; }
set { _rows = value; }
}
I've tried mapping it a couple ways -
publich ProjCTSagaMap() // ctor for my ClassMap subclass
{
/*HasMany(x => x.Rows)
.AsMap("ProjectNumber")
.KeyColumns.Add("Row", mapping => mapping.Name("Row").SqlType("nvarchar").Not.Nullable())
.Cascade.AllDeleteOrphan()
.Table("ProjCtSagaRow");*/
HasMany(x => x.Rows)
.Table("ProjCtSagaRow")
.KeyColumn("CorrelationId")
.Element("Row")
.AsMap("ProjectNumber")
.Inverse();
}
And I've written a unit test to test the mapping -
[Test] public void ProjCtSagaMapTest()
{
using (var session = Utility.CreateSession<ProjCtSaga, ProjCtSagaMap>())
{
new PersistenceSpecification<ProjCtSaga>(session)
.CheckReference(
i => i.Rows,
new Dictionary<string, string> { { "key", "value" } },
new DictionaryComparer<string, string>())
.VerifyTheMappings();
}
I'm not sure where the problem actually lies, in the mapping, or in the test. The actual error in the unit test is -
NHibernate.MappingException occurred
Message=No persister for: System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
Source=NHibernate
StackTrace:
at NHibernate.Impl.SessionFactoryImpl.GetEntityPersister(String entityName)
at NHibernate.Impl.SessionImpl.GetEntityPersister(String entityName, Object obj)
at NHibernate.Event.Default.AbstractSaveEventListener.SaveWithGeneratedId(Object entity, String entityName, Object anything, IEventSource source, Boolean requiresImmediateIdAccess)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.SaveWithGeneratedOrRequestedId(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.EntityIsTransient(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveEventListener.PerformSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Event.Default.DefaultSaveOrUpdateEventListener.OnSaveOrUpdate(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.FireSave(SaveOrUpdateEvent event)
at NHibernate.Impl.SessionImpl.Save(Object obj)
at FluentNHibernate.Testing.PersistenceSpecification`1.TransactionalSave(Object propertyValue) in d:\Builds\FluentNH\src\FluentNHibernate\Testing\PersistenceSpecification.cs:line 79
InnerException:
Can someone explain how to map an IDictionary with a ClassMap and test that mapping with PersistenceSpecification...VerifyMappings()?
PS - The version of FluentNHibernate is 1.3.0.717, and NHibernate version is 3.2.0.4000. I did have to compile it locally for one minor and unrelated change.
Thank you!
Here's the rest of the error that I'm getting now -
System.FormatException : Failed to convert parameter value from a String to a Int32.
----> System.FormatException : Input string was not in a correct format.
at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
at System.Data.SqlClient.SqlParameter.GetCoercedValue()
at System.Data.SqlClient.SqlParameter.Validate(Int32 index, Boolean isCommandProc)
at System.Data.SqlClient.SqlCommand.BuildParamList(TdsParser parser, SqlParameterCollection parameters)
at System.Data.SqlClient.SqlCommand.BuildExecuteSql(CommandBehavior behavior, String commandText, SqlParameterCollection parameters, ref _SqlRPC rpc)
at System.Data.SqlClient.SqlCommand.AddBatchCommand(String commandText, SqlParameterCollection parameters, CommandType cmdType)
at System.Data.SqlClient.SqlCommandSet.ExecuteNonQuery()
at NHibernate.AdoNet.SqlClientBatchingBatcher.DoExecuteBatch(IDbCommand ps)
at NHibernate.AdoNet.AbstractBatcher.ExecuteBatchWithTiming(IDbCommand ps)
at NHibernate.AdoNet.AbstractBatcher.ExecuteBatch()
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
at FluentNHibernate.Testing.PersistenceSpecification`1.TransactionalSave(Object propertyValue) in d:\Builds\FluentNH\src\FluentNHibernate\Testing\PersistenceSpecification.cs: line 80
at FluentNHibernate.Testing.PersistenceSpecification`1.VerifyTheMappings(T first) in d:\Builds\FluentNH\src\FluentNHibernate\Testing\PersistenceSpecification.cs: line 52
at Appalappa.Tests.ProjCtTests.ProjCtSagaMapTest() in ProjCtTests.cs: line 32
--FormatException
at System.Number.StringToNumber(String str, NumberStyles options, ref NumberBuffer number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at System.Data.SqlClient.SqlParameter.CoerceValue(Object value, MetaType destinationType)
Solution
get rid of .Inverse();
since the element can not maintain the backreference, it is a string.
CheckReference
is for References but you have a collection. Use CheckEnumerable
or CheckList
Update: this works for me
.CheckComponentList(p => p.Rows,
new[] { new KeyValuePair<string, string>("1", "2") },
(p, item) => p.Rows.Add(item));