среда, 25 июля 2012 г.

Fluent NHibernate: маппинг перечислений(Enum)

Если поискать, то можно найти достаточно много способов маппинга перечислений в NHibernate, я для себя выбрал вариант, при котором значения перечисления сохраняются, как строки в БД, используя созданный пользовательский тип данных.
Рассмотрим сущность Продукт, которая может иметь несколько полей, и одно из которых - это количество продукта, имеющее определенную для каждого Продукта единицу измерения. Например, молоко в литрах, сахар в граммах, яйца в штуках и т.д..
В коде, это будет выглядеть так:

public enum UnitType

{

    Piece,

    Milliliter,

    Gram

}

class Product : EntityBase

{

   /**~~~**/

   public virtual UnitType UnitType { get; set; }

   /**~~~**/

}

Для осуществления маппинга перечисления, во-первых, необходимо реализовать интерфейс IUserType:

public class UnitTypeEnumMap : IUserType
{
    public bool Equals(object x, object y)
    {
        return object.Equals(x, y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        object r = rs[names[0]];
        var value = (string)r;

        if (string.IsNullOrEmpty(value))
            throw new Exception("Invalid Unit Type");

        switch (value)
        {
            case "P":
                return UnitType.Piece;
            case "Ml":
                return UnitType.Milliliter;
            case "G":
                return UnitType.Gram;

            default:
                throw new Exception("Invalid Unit Type");
        }
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        object paramVal = 0;
        switch ((UnitType)value)
        {
            case UnitType.Piece:
                paramVal = "P";
                break;
            case UnitType.Milliliter: 
                paramVal = "Ml";
                break;
            case UnitType.Gram:
                paramVal = "G";
                break;
            default:
                throw new Exception("Invalid Unit Type");
        }
        var parameter = (IDataParameter)cmd.Parameters[index];
        parameter.Value = paramVal;
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return cached;
    }

    public object Disassemble(object value)
    {
        return value;
    }

    public SqlType[] SqlTypes
    {
        get { return new SqlType[] {new StringSqlType()}; }
    }

    public Type ReturnedType
    {
        get { return typeof (UnitType); }
    }

    public bool IsMutable
    {
        get { return false; }
    }
}


Во-вторых, при маппинге сущности Продукт используется свойство CustomType:
Map(x => x.UnitType).CustomType<UnitTypeEnumMap>();


Посмотрев на код становится ясно, что вся логика скрыта в 2-х функциях NullSafeGetNullSafeSet и свойстве public SqlType[] SqlTypes. 
Функция NullSafeGet реализует логику чтения пользовательского типа, учитывая возможные null значения, а функция NullSafeSet  - логику записи, соответственно.
Свойство SqlTypes отвечает за то, какой внутренний тип данных БД будет использоваться для хранения пользовательского типа. Возвращается массив значений, так как пользовательский тип может занимать не один столбец в таблице данных.

3 комментария:

  1. Ahaa, its nice conversation concerning this post at this place
    at this weblog, I have read all that, so at this time me also commenting here.
    Also visit my blog post Hainan Airlines

    ОтветитьУдалить
  2. I blog frequently and I seriously thank you for your information.

    This article has really peaked my interest.
    I will book mark your site and keep checking for new
    information about once a week. I subscribed to your RSS feed as well.
    My web site - topografía

    ОтветитьУдалить
  3. Thank you a lot for sharing this with all folks you really realize what you're talking about! Bookmarked. Please also talk over with my site =). We could have a link trade arrangement among us
    my site :: bacalao

    ОтветитьУдалить