Два отношения многие-к-одному, ссылающиеся на один и тот же столбец NHibernate - PullRequest
0 голосов
/ 29 апреля 2020

Последние полдня искали и подошли dry. По сути, я работаю над унаследованным приложением, ранее существовавшая конфигурация NHibernate отображала одно свойство / столбец на конце DB в два разных отношения «многие-к-одному» и, следовательно, два разных свойства C#. Таблицы categories и types используют одни и те же первичные ключи / индексы, но в MySQL или NHibernate нет явной связи.

Раньше эти таблицы были «только для чтения», и они работали в приложении, избегая выставлять это как проблему. Но недавно мне было поручено разрешить пользователям изменять и сохранять изменения в таблице grid (имеет другие свойства, которые я не перечислил для краткости).

NHibernate выдал исключение crypti c, связанное, я полагаю, с тем, что он пытается сохранить два отдельных объекта уровня «Домен» в одну ссылку на столбец. Я просмотрел general_log и запрос на обновление не дошел до базы данных. Закомментирование строки «Cat» в конфигурационном файле .hbm.xml устранило «ошибку», но как я могу исправить отображение таким образом, чтобы Cat и GridType должны иметь одинаковое значение ID, и я могу сохранить grid переходит обратно в БД?

public class Grid
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual GridType GridType { get; set; }
    public virtual Cat Cat { get; set; }
    ...
}

Схема БД выглядит следующим образом (поддерживая существующую странную настройку):

CREATE TABLE `categories` 
  `CatID` smallint(4) NOT NULL,
  `Name` varchar(50) DEFAULT NULL,
  ...
  PRIMARY KEY (`CatID`)

CREATE TABLE `types`
  `TypeID` smallint(4) NOT NULL,
  `Name` varchar(50) DEFAULT NULL,
  ...
  PRIMARY KEY (`TypeID`)

CREATE TABLE `grid` 
  `GridID` smallint(6) NOT NULL AUTO_INCREMENT,
  `Name` varchar(255) DEFAULT NULL,
  `TypeID` smallint(4) NOT NULL,
  ...
  PRIMARY KEY (`GridID`),
  KEY `GridTypeId` (`TypeID`),
  CONSTRAINT `GridTypeId` FOREIGN KEY (`TypeID`) REFERENCES `types` (`TypeID`),

Таблица grid ссылается на таблицу types через внешний ключ в MySQL , но ничто на DB-конце не связывает его с categories. Конфигурация NHibernate в настоящее время настроена так, за исключением того, что ранее конфигурация "grid" ранее была mutable="false" и cache usage="read-only":

  <class name="Grid, Domain" table="grid" lazy="true">
    <cache usage="read-write" />
    <id name="Id" column="GridID" unsaved-value="0">
      <generator class="identity" />
    </id>
    ...
    <many-to-one name="GridType" column="TypeID" fetch="join" not-null="true" />
    <many-to-one name="Cat" column="TypeID" not-null="true" />
  </class>

  <class name="Cat, Domain" table="categories" lazy="true" mutable="false">
    <cache usage="read-only"/>
    <id name="Id" column="CatID" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Name" />
    ...
  </class>

  <class name="GridType, Domain" table="types" mutable="false">
    <cache usage="read-only"/>
    <id name="Id" column="TypeID"/>
    <property name="Name" />
    ...
  </class>

. Попробую убедить моего босса, что это стоит реструктурировать. потому что вся эта область БД - беспорядок, но это - устаревшее приложение; поэтому я хочу знать, какие у меня варианты, в зависимости от того, как выглядит наша готовность к будущему развитию.


Редактировать : Судебный процесс, предложенный Радимом Келером ниже. Единственным недостатком было то, что (a) Кто-то мог переключить значение Cat и ошибочно полагать, что он внес изменения в БД, но это не будет сохраняться. И (б) если кто-то обновит GridType, он обновит БД, но не кеш; Cat будет оставаться старым значением до тех пор, пока NHibernate снова не будет извлечен из БД (т.е. идентификаторы Cat и GridType будут "не синхронизированы", что было частью моего вопроса).

Исправление I Испытание "когда значения GridType / Cat на Grid установлены, установите другое, выбрав соответствующий идентификатор из кэша". Также будет препятствовать тому, чтобы кто-то установил тип сетки / кошку, которая может не существовать в другой таблице.

public class Grid {

    ...

    private GridType _gridType;
    private Cat _cat;

    public virtual GridType GridType
    {
        get => _gridType;
        set
        {
            var cat = _catRepository.GetById(value.Id);
            _cat = cat ?? throw new InvalidOperationException("GridType is not valid Cat");
            _gridType = value;
        }
    }

И повторите выше для public virtual Cat Cat. Если кто-то видит проблему с этим, пожалуйста, не стесняйтесь оставлять комментарий.

1 Ответ

1 голос
/ 30 апреля 2020

Мы можем использовать один столбец в отображении для нескольких целей ... но только одно свойство может быть редактируемым ... все остальные должны быть доступны только для чтения. Мы можем использовать insert="false" update="false"

Это будет работать в нашем случае:

<many-to-one name="GridType" column="TypeID" ... />
<many-to-one name="Cat"      column="TypeID" insert="false" update="false" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...