NHibernate: методы Get и Set пользовательского свойства Access не вызывают - PullRequest
2 голосов
/ 19 ноября 2010

Я пытаюсь отобразить в поле базы данных ("LS_RECNUM") возможные значения NULL, 'M' и 'F' в свойство с типом перечисления Gender.

Отображение выглядит так:

Map(x => x.Gender).Column("LS_GENDER").Access.Using<GenderPropertyAccessor>();

... и класс GenderPropertyAccessor выглядит следующим образом:

using System;
using System.Collections;
using System.Reflection;
using Kctc;
using NHibernate.Engine;
using NHibernate.Properties;

public class GenderPropertyAccessor : IPropertyAccessor
{
  #region Setter

  private class GenderGetterSetter : IGetter, ISetter
  {
    PropertyInfo _property;
    public GenderGetterSetter(PropertyInfo property)
    {
      if (property == null) throw new ArgumentNullException("property");
      if (property.PropertyType != typeof(Gender)) throw new ArgumentException("property");
      _property = property;
    }

    public void Set(object target, object value) //Convert string to enum
    {
      _property.SetValue(target, GetGenderFromString(value), null);
    }

    public object Get(object target) //Convert enum back to string
    {
      Gender gender = (Gender)_property.GetValue(target, null);
      return SetGenderToString(gender);
    }

    /// <summary>
    /// Interprets the supplied string as a gender.
    /// </summary>
    /// <param name="strGender">The gender as either 'F' or 'M'.</param>
    /// <returns></returns>
    private Gender GetGenderFromString(object strGender)
    {
      if (strGender == null) return Gender.Unknown;
      switch (strGender.ToString().ToLower())
      {
        case "f":
          return Gender.Female;
        case "m":
          return Gender.Male;
        default:
          return Gender.Unknown;
      }
    }

    /// <summary>
    /// Sets the supplied Gender to the appropriate 'M' or 'F' value.
    /// </summary>
    /// <param name="objGender">The gender.</param>
    /// <returns></returns>
    private string SetGenderToString(object objGender)
    {
      Gender gender = (Gender) objGender;
      switch (gender)
      {
        case Gender.Female:
          return "F";
        case Gender.Male:
          return "M";
        default:
          return null;
      }
    }

    public MethodInfo Method
    {
      get { return null; }
    }

    public string PropertyName
    {
      get { return _property.Name; }
    }

    public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session)
    {
      return Get(owner);
    }

    public Type ReturnType
    {
      get { return typeof(byte[]); }
    }
  }

  #endregion

  public IGetter GetGetter(Type theClass, string propertyName)
  {
    return new GenderGetterSetter(theClass.GetProperty(propertyName));
  }

  public ISetter GetSetter(Type theClass, string propertyName)
  {
    return new GenderGetterSetter(theClass.GetProperty(propertyName));
  }

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

Не особенно знаком с рефлексией, я совсем не уверен, что методы Get и Set были реализованы правильно.

Когда я пытаюсь это сделать, я все равно получаю сообщение об ошибке «Не могу проанализировать F как пол». Я попытался отладить класс GenderPropertyAccessor. Соответствующая строка (показанная выше) в файле отображения выполняется правильно, как и конструктор для класса GenderGetterSetter, но методы Get и Set никогда не вызываются !!!

Может кто-нибудь сказать мне, что я могу делать неправильно?

1 Ответ

3 голосов
/ 19 ноября 2010

Я бы использовал реализацию IUserType для этого. Вот хороший простой пример . В методах NullSafeGet и NullSafeSet вы будете преобразовывать строку в перечисление и обратно соответственно. Также важно, чтобы ваша реализация Equals была правильной, чтобы NHibernate обнаруживал изменения.

Сопоставить свойство для использования пользовательского типа легко:

Map(x => x.Gender).Column("LS_GENDER").CustomType(typeof(MyUserType));
...