2011-07-06 4 views
0

В вопросе Mapping to an Enum bit flag in Nhibernate принятый ответ предлагает просто использовать целое поле для хранения битовой маски типа перечисления. Хотя это, безусловно, работает, я бы предпочел не использовать этот подход, потому что он запутывает информацию в базе данных.Сопоставление битового поля (FlagsAttribute) с несколькими столбцами с использованием NHibernate?

Скажем, у меня есть это перечисление:

[Flags] 
public enum Status 
{ 
    None = 0, 
    Foo = 1, 
    Bar = 2, 
    Baz = 4 
} 

Я хотел бы использовать следующую схему для его представления:

CREATE TABLE Widgets 
(
    Id int NOT NULL IDENTITY(1, 1) PRIMARY KEY, 
    Description nvarchar(100) NOT NULL, 
    -- Status fields start here 
    IsFoo bit NOT NULL, 
    IsBar bit NOT NULL, 
    IsBaz bit NOT NULL 
) 

Могу ли я сделать это с помощью NHibernate - желательно без большого некрасиво хаки? Если да, то как?

Если нет, существуют ли какие-либо альтернативы, которые поддерживают обнаружение данных, кроме определения каждой возможной комбинации флагов в таблице конфигурации?

(Примечание: Я бы предпочел решение Fluent NHibernate, но я, вероятно, может запутать через отображение XML.)

+0

Почему вы отказались от типа композитного пользователя, упомянутого в статье, я бы подумал, что он удовлетворит ваши потребности. –

+0

@Mike: Возможно, вы правы, и это может быть решение; для меня невозможно сказать, основываясь на этом ответе, который содержит только ссылку, которая выводит меня на страницу, посвященную совершенно другой проблеме. Если вы можете объяснить, как адаптировать этот подход к битовому полю, я с радостью принимаю такой ответ. – Aaronaught

ответ

0

ну, это, по крайней мере, немного некрасиво:
Вы можете отобразить те 3 столбца в частные поля вашей сущности, а затем вычислить свойство Status из этих трех полей.
что-то эффект:

public class Kuku 
{ 
    private virtual bool IsFoo {get; set;} 
    private virtual bool IsBar {get; set;} 
    private virtual bool IsBaz {get; set;} 

    public virtual Status Stat 
    { 
     get 
     { 
     Status retval = Status.None; 
     if (IsFoo) 
     { 
      retVal |= Status.Foo; 
     } 
     //etc... 
     } 
     set 
     { 
     IsFoo = value & Status.Foo; 
     //etc... 
     } 
    } 
} 
2

Извиняюсь за не полный ответ здесь, я изо всех сил настройки NHib/свободно на этой машине. Я взял старый пользовательский тип, который у меня был, и изменил его, чтобы соответствовать вашему перечислению статуса. Я думаю, что в более поздних версиях nHibernate некоторые интерфейсы методов могли быть изменены, но я думаю, что это дает хорошую отправную точку.

class StatusUserType : ICompositeUserType 
    { 
     public object GetPropertyValue(object component, int property) 
     { 
      // 0 = foo 
      // 1 = bar 
      // 2 = baz 
      Status status = (Status)component; 
      if (property == 0) 
      { 
       return status |= Status.Foo; 
      } 
      else if (property == 1) 
      { 
       return status |= Status.Bar; 
      } 
      else 
      { 
       return status |= Status.Baz; 
      } 
     } 

     public void SetPropertyValue(object component, int property, object value) 
     { 
      throw new NotImplementedException(); 

     } 
     public new bool Equals(object x, object y) 
     { 
      if (x == y) return true; 
      if (x == null || y == null) return false; 
      return x.Equals(y); 
     } 


     public object NullSafeGet(System.Data.IDataReader dr, string[] names, ISessionImplementor session, object owner) 
     { 
      if (dr == null) 
      { 
       return null; 
      } 
      string fooColumn = names[0]; 
      string barColumn = names[1]; 
      string bazColumn = names[2]; 

      bool isFoo = NHibernateUtil.Boolean.NullSafeGet(dr, fooColumn, session, owner); 
      bool isBar = NHibernateUtil.Boolean.NullSafeGet(dr, barColumn, session, owner); 
      bool isBaz = NHibernateUtil.Boolean.NullSafeGet(dr, bazColumn, session, owner); 

      Status status = (isFoo ? Status.Foo : Status.None) | (isBar ? Status.Bar : Status.None) | (isBaz ? Status.Baz : Status.None); 
      return status; 

     } 

     public void NullSafeSet(System.Data.IDbCommand cmd, object value, int index, ISessionImplementor session) 
     { 
      if (value == null) 
       return; 

      Status status = (Status)value; 

      bool isFoo = ((status & Status.Foo) != 0); 
      bool isBar = ((status & Status.Bar) != 0); 
      bool isBaz = ((status & Status.Baz) != 0); 


      NHibernateUtil.Boolean.NullSafeSet(cmd, isFoo, index, session); 
      NHibernateUtil.Boolean.NullSafeSet(cmd, isBar, index + 1, session); 
      NHibernateUtil.Boolean.NullSafeSet(cmd, isBaz, index + 2, session); 
     } 


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


     public object Disassemble(object value, ISessionImplementor session) 
     { 
      return DeepCopy(value); 
     } 


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


     public string[] PropertyNames 
     { 
      get { return new string[3] { "IsFoo", "IsBar", "IsBaz" }; } 
     } 


     public IType[] PropertyTypes 
     { 
      get 
      { 
       return new IType[3] { NHibernateUtil.Boolean, NHibernateUtil.Boolean, NHibernateUtil.Boolean }; 
      } 
     } 

     public Type ReturnedClass 
     { 
      get { return typeof(Status); } 
     } 


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

Некоторые определенные ошибки здесь, такие как тесты isXyz (должны быть '(status & Status.Foo)! = 0'), но это выглядит как правильная стратегия, по крайней мере. – Aaronaught

+0

Ах спасибо, я не часто работаю с Flags, поэтому я просто догадался, я обновил ответ, чтобы отразить это. –

Смежные вопросы