Nhibernate Multiple table имеет отношение «один ко многим» к конкретной таблице

У меня есть таблица, назовем А. В А есть поле - objId.

Есть и другие таблицы, назовем их B, C и D., в которых есть список записей A. Запись должна быть создана путем добавления записи A в список записей A одной из таблиц B, C и D. Поле objId должно быть PK (id) записи B/C/D У кого есть список А.

что означало - objId - это FK для многих таблиц. Я начинаю с таблицы B. Но после создания таблицы B создается поле objId таблицы A. а что теперь будет с таблицами C и D? Они не могут снова создать столбец objId в таблице.

Код:

<id name="Id">
  <generator class="guid" />
</id>

<bag name="As" cascade="All">
  <key column="ObjId" />
  <one-to-many class="A" />
</bag>

<class name="A">
<id name="Id">
  <generator class="guid" />
</id>
<property name="ObjId" />

public class B
{
    public virtual Guid Id { get; set; }
    public virtual IList<A> As{ get; set; }
}

public class A
{  
    public virtual Guid Id { get; set; }
    public virtual string ObjId { get; set; }
}

добавление записи A к B:

       this.Update(session =>
       {
           var bRecord = ....;

           bRecord.As.Add(new ARecord {
                 ...
          });

             session.Update(bRecord);
       });

Как мне создать правильную ассоциацию?


person Shir    schedule 20.03.2014    source источник


Ответы (1)


В общем, есть больше способов, как справиться с этим сценарием - каждый из них потребует некоторой корректировки/расширения. т.е. вы все равно должны изменить структуру своей БД

Если бы на экземпляр A могли ссылаться все B, C, D, единственным способом было бы введение столбцов внешнего ключа BObjectId, CObjectId, DObjectId.

Если экземпляр A может использоваться исключительно одним из них (B, C, D), нам понадобится новый столбец, назовем его Discriminator

<class name="A">
  <id name="Id" generator="guid" />
 <property name="ObjId" />
 <property name="Discriminator" />
</class>

Теперь нам нужно правильно ввести значение в Discriminator в нашем коде C#. Если A назначено B, мы должны заполнить 'B'

var a = new A();
b.AddA(a);

где реализация должна быть такой.

public virtual void AddA(A a)
{
    As.Add(a);
    a.ObjectId = this.ID
    a.Discriminator = 'B'
}

ПРИМЕЧАНИЕ. В этом случае мы присваиваем идентификатор ObjectId. Это работает, но только если идентификатор уже назначен. Это не сработает, если объект B временный, со значением ID по умолчанию. В этом случае нам нужно будет создать обходной путь. Например. Flush() для B, а затем назначьте ссылку...

Итак, нам удалось правильно управлять/заполнять/вставлять значение Дискриминатора в экземпляр/запись A. Теперь мы можем использовать его также для сопоставления. Отображение пакетов B, C, D будет очень похожим:

<class name="A">
  <bag name="As" cascade="All" batch-size="25"
    where=" Discriminator = 'B' " >
      <key column="ObjId" />
      <one-to-many class="A" />
  </bag>

where=" Discriminator = 'B' " — это хороший способ NHibernate внедрить фильтр в нашу коллекцию. Примените то же самое для C, D... и...

person Radim Köhler    schedule 21.03.2014
comment
Большое спасибо за Вашу помощь. Как вы говорите: «В общем, есть больше способов справиться с этим сценарием». кто они такие? Является ли способ, который вы написали, лучшим способом? - person Shir; 24.03.2014
comment
Отлично, если это хоть как-то помогло. Наслаждайтесь NHiberante ;) - person Radim Köhler; 24.03.2014