2

I have a class that contains a collection of enumeration as follows.

public enum TransactionType
{
  ...
}

public class PaymentMethod
{
  ...
  public virtual IList<TransactionType> SupportedTransactionTypes { get; set; }
}

Other references to the TransactionType enumeration are working correctly but with this collection I get an exception: "NHibernate.MappingException : Association references unmapped class: mynamespace.TransactionType".

Looking around it seems like I needed to specify the type of element mapping, i.e. one-to-many, element, or composite-element.

I have setup the following override mappings for the PaymentMethod class:

mapping.HasMany(x => x.TransactionTypes)
  .Element("TransactionTypeId"), x => x.Type<TransactionType>());

But this causes the following exception...

Validation failed: System.NullReferenceException: Object reference not set to an instance of an object. at FluentNHibernate.Conventions.Inspections.OneToManyInspector.get_Class() in e:\horn.horn\orm\fluentnhibernate\Working\src\FluentNHibernate\Conventions\Inspections\OneToManyInspector.cs:line 40 at FluentNHibernate.Conventions.ProxyConvention.Apply(ICollectionInstance instance) in e:\horn.horn\orm\fluentnhibernate\Working\src\FluentNHibernate\Conventions\ProxyConvention.cs:line 79 at FluentNHibernate.Visitors.ConventionVisitor.Apply[TInspector,TInstance](IEnumerable conventions, TInstance instance) in e:\horn.horn\orm\fluentnhibernate\Working\src\FluentNHibernate\Visitors\ConventionVisitor.cs:line 269 at ...

I have tried a lot of different variations on the mapping, including TableName, KeyColumn and anything else I can think of but I can't get this mapping to work.

Any help appreciated...

3 Answers 3

3

Perhaps this is a recent fix in FluentNHibernate, but this works with FluentNH v1.2.0.712. I'm fairly confident that NHibernate with plain *.hbm.xml mappings has supported this type of mapping for years.

This is the automapping override that worked for me:

mapping.HasMany(x => x.SupportedTransactionTypes)
    .Element("TransactionTypeId");

...which results in this XML...

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="so.Q2676867.PaymentMethod, so, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`PaymentMethod`">
    <id access="backfield" name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <bag name="SupportedTransactionTypes">
      <key>
        <column name="PaymentMethod_id" />
      </key>
      <element type="so.Q2676867.TransactionType, so, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
        <column name="TransactionTypeId" />
      </element>
    </bag>
  </class>
</hibernate-mapping>

... and these tables:

create table [PaymentMethod] (
    Id INT IDENTITY NOT NULL,
   primary key (Id)
)

create table SupportedTransactionTypes (
    PaymentMethod_id INT not null,
   TransactionTypeId INT null
)

alter table SupportedTransactionTypes 
    add constraint FK738E3751B597A1C 
    foreign key (PaymentMethod_id) 
    references [PaymentMethod]

... which is exactly what I would expect. Yay NHibernate!

Sign up to request clarification or add additional context in comments.

Comments

1

You could persist the collection in the database as a pipe-delimited string...

    protected string _enumCollection = "";    
    public virtual ISet<MyEnum> EnumCollection
    {
        get
        {
            var set = new HashedSet<MyEnum>();

            if (string.IsNullOrEmpty(_enumString))
                return set;

            _enumCollection.Split(new[] {"|"}, StringSplitOptions.None).ToList()
                .ForEach(
                    x => set.Add((MyEnum)(Int32.Parse(x)))
                );
            return new HashedSet<MyEnum>(set);
        }
        set { _enumCollection = string.Join("|", value.Select(x => ((int)x).ToString()).ToArray()); }
    }

and then map to the string backing field:

Map(x => x.EnumCollection).CustomType(typeof(string)).Access.CamelCaseField(Prefix.Underscore);

You'll need to use helper methods to add/remove enums rather than using the methods on the collection itself in order to update the backing field.

public virtual void AddEnum(MyEnum enum)
        {
            if (!EnumCollection.Contains(enum))
            {
                var set = EnumCollection; //you need to get the collection
                set.Add(enum); //add enum to it
                EnumCollection= set; //then set the set again
            }
        }

        public virtual void RemoveEnum(MyEnum enum)
        {
            if (EnumCollection.Contains(enum))
            {
                var set = EnumCollection; //get collection
                set.Remove(enum); //add enum 
                EnumCollection= set; //re-set collection
            }
        }

Hope this helps.

Comments

0

I dont think you can map a collection of enums. You certainly couldnt a year or so ago

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.