Stefan Steinegger
Stefan Steinegger

Reputation: 64628

NHibernate CompositeUserType: How to specify Sql Types?

Using NH 2.0, I have a custom type. It is composed of four properties, so I implemented ICompositeUserType.

I want to specify length and precision for the string and decimal properties within the user type, to avoid specifying it with every usage in the mapping files.

But there is only a PropertyTypes property to implement, which returns IType. The funny thing is, the IUserType has a SqlTypes property, ICompositeUserType does not.

Thanks a lot.

Upvotes: 4

Views: 2243

Answers (2)

Stefan Steinegger
Stefan Steinegger

Reputation: 64628

I found the solution, it is pretty simple. I have to create the NHibernate types using the TypeFactory:

public IType[] PropertyTypes
{
  get
  {
    return new []
    {
      TypeFactory.GetDecimalType(36, 18),
      TypeFactory.GetStringType(100)
    }
  }
}

Upvotes: 1

bbmud
bbmud

Reputation: 2688

I recommend downloading source code for this type of digging (NH 2.0).

First take a look at TypeFactory.HeuristicType method, which builds the IType instance.

...
else if (typeof(ICompositeUserType).IsAssignableFrom(typeClass))
{
    type = new CompositeCustomType(typeClass, parameters);
}
else if (typeof(IUserType).IsAssignableFrom(typeClass))
{
    type = new CustomType(typeClass, parameters);
}
...

So if your custom type implements ICompositeUserType it gets instantiated as CompositeCustomType class. This eliminates the possibility to implement both ICompositeUserType and IUserType interfaces.

Now let's take a look into CompositeCustomType

public override SqlType[] SqlTypes(IMapping mapping)
{
    IType[] types = userType.PropertyTypes;
    SqlType[] result = new SqlType[GetColumnSpan(mapping)];
    int n = 0;
    for (int i = 0; i < types.Length; i++)
    {
        SqlType[] sqlTypes = types[i].SqlTypes(mapping);
        for (int k = 0; k < sqlTypes.Length; k++)
        {
            result[n++] = sqlTypes[k];
        }
    }
    return result;
}

So it takes your types returned from PropertyTypes and builds the SqlType for each property. This means that providing your own user type wrappers for each property will do the trick.

Upvotes: 3

Related Questions