Свободный код для отображения IDictionary <SomeEntity, int>? - PullRequest
5 голосов
/ 01 сентября 2009

Я пытаюсь выяснить, как сопоставить свойство IDictionary в версии 1.0 RTM.

Насколько я понимаю, это означает троичную ассоциацию.

Пример:

class Bar
{
    public IDictionary<SomeEntity, int> Foo {get; set;}
}

Bar.hbm.xml будет содержать:

<map name="Foo" table="BarFooTable">
    <key column="..."/>
    <index-many-to-many class="SomeEntity" column="SomeEntity_Id"/>
    <element column="Value" type="int"/>
</map>

Что мне нужно написать в беглом nhibernate для создания этого xml-файла сопоставления?

Интересно, что ключ является типом сущности, а значение - типом значения. (редактировать: по крайней мере, это, кажется, отличается от других примеров и вопросов, связанных с stackoverflow или группами google, которые представляют собой значение-значение или ключ-ключ)

После долгих экспериментов я могу создать отображение для IDictionary<SomeEntity,SomeEntity> (чистые типы сущностей):

HasManyToMany(x => x.Foo)
        .AsMap("Key")
        .AsTernaryAssociation("Key2", "Value")
        ; 

Я также могу создать отображение для IDictionary<int,int> (типы с чистыми значениями):

HasMany(x => x.Foo)
    .AsMap<int>("Key")
    .Element("Value")
    ;

Я даже могу получить какой-то способ создания сопоставления для IDictionary<int, SomeValue), хотя ни один из них не будет принят NHibernate.

Но я не могу понять, как создать отображение для IDictionary<SomeValue, int>, что я и хочу. Может кто-нибудь дать несколько советов?

Ответы [ 4 ]

2 голосов
/ 30 июня 2010
HasMany(x => x.Foo)
    .KeyColumn("BarId")
    .Element("IntValue")
    .AsMap<SomeEntity>("SomeEntityId")
    .AsTernaryAssociation("SomeEntityId");
1 голос
/ 08 сентября 2009

Я столкнулся с той же проблемой и не был доволен смешиванием отображений беглого и hbm. Вы можете увидеть мое исправление здесь .

0 голосов
/ 22 сентября 2014

Учитывая эти (упрощенные) классы:

class LetterTemplate
{
  IDictionary<State, FieldAccessOptionality> StateAccess {get; protected set;}
}

class State
{
}

enum FieldAccessOptionality
{
}

Это сработало для меня.

(Да, я знаю, что значением является Enum, но принцип такой же, как у int).

  HasManyToMany(x => x.StateAccess)
    .ParentKeyColumn("`letter_template`")
    .ChildKeyColumn("`state`")
    .AsMap<State>("`state`")
    .Element("`access`",
      p =>
        p.Type<IntEnumType<FieldAccessOptionality>>())
    .AsTernaryAssociation("`state`", "`access`")
    .Table("`letter_template_state_access`");

Обратите внимание на класс IntEnumType <>, который преобразует перечисление в int для NHibernate. Если вы отображаете int вместо enum, вы можете просто использовать стандартный NHibernate Int32Type IUserType. Полный список для этого класса выглядит следующим образом:

public class IntEnumType<T> : IUserType where T : struct
{
  public object Assemble(object cached, object owner)
  {
    return cached;
  }

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

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

  public new bool Equals(object a, object b)
  {
    return Object.Equals(a, b);
  }

  public int GetHashCode(object x)
  {
    if (x == null)
      return 0;
    else
      return x.GetHashCode();
  }

  public bool IsMutable
  {
    get { return false; }
  }

  public object NullSafeGet(IDataReader rs, string[] names, object owner)
  {
    object result = NHibernateUtil.Int32.NullSafeGet(rs, names);
    if (result == null)
    {
      return null;
    }
    else
    {
      Type typ = Enum.GetUnderlyingType(typeof(T));
      result = Convert.ChangeType(result, typ);
      return Enum.ToObject(typeof(T), result);
    }
  }

  public void NullSafeSet(IDbCommand cmd, object value, int index)
  {
    if (value == null)
      ((IDataParameter)cmd.Parameters[index]).Value = DBNull.Value;
    else
      ((IDataParameter)cmd.Parameters[index]).Value = Convert.ChangeType(value, typeof(int));
  }

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

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

  public SqlType[] SqlTypes
  {
    get
    {
      SqlType type = new SqlType(DbType.Int32);
      return new SqlType[] { type };
    }
  }

}
0 голосов
/ 03 сентября 2009

Кажется, у нас та же проблема:

Как отобразить это в Fluent.NHibernate

Я просто использовал hbm.xml (который был сгенерирован Fluent.Nhibernate в моем проекте), и немного изменил его. Если вы установите

 .Mappings(m =>
   {                                             
       m.FluentMappings.AddFromAssemblyOf<DomainClass>()
                       .ExportTo("Path");
       m.HbmMappings.AddFromAssemblyOf<DomainClass>();
   })

и если у вас есть и ClassMap, и hbm.xml, hbm.xml должен переопределить ClassMap, так что вы будете в порядке, пока он не исправлен.

Мне также нужен естественный идентификатор для моего класса, и он также не поддерживается с Fluent.Nhibernate, поэтому у меня не было выбора, кроме как использовать hbm.xml

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...