Коллекция карт Hibernate с постоянным ключом - PullRequest
2 голосов
/ 17 ноября 2009

Я пытаюсь отобразить коллекцию (типа map), используя внешний ключ и фиксированное значение в качестве аргумента ключ / отображение.

У меня есть несколько таблиц типов продуктов и языковая таблица, содержащая такие вещи, как названия продуктов и т. Д.

Теперь предположим, что у нас есть таблица аксессуаров, которая содержит (очевидно) аксессуары, тогда имя аксессуара сохраняется в языковой таблице с помощью language.id = accessory.id и language.type = 'accessory'. Ключ карты должен быть полем language.lang, строкой кода языка.

Теперь, независимо от того, что я пробовал, я просто не могу получить правильную часть "language.type = 'accessory" ", не нравится элемент с несколькими ключами, который, в свою очередь, не разрешит элементы в любом случае.

Я также пробовал это с составным компонентом, как foreignKey, с константой, установленной по умолчанию, но это тоже не сработало:

<class name="AccessoryTypes"
    table="accessorytypes">
    <id name="id" column="id" type="java.lang.Long" unsaved-value="0">
        <generator class="identity"></generator>
    </id>
    <map name="Name" table="ProductCode">
        <key column="CompositeId" />
        <map-key column="Language" type="string" />
        <one-to-many class="ProductCode" />
    </map>
</class>

<class name="Language"
        table="Language">
        <composite-id name="compositeId" class="languageKey">
            <key-property name="Type"></key-property>
            <key-property name="Id"></key-property>
        </composite-id>
        <property name="Lang" type="string"></property>
        <property name="Value"></property>
    </class>

конечно с соответствующими классами. Этот подход не дает ошибок, но также не заполняет HashMap класса Accessory ...

любая помощь будет оценена, спасибо.

[править] Теперь я попробовал это с помощью свойства ref, как предложил Зиодберг, сначала не с таким:

<class name="AccessoryTypes"
        table="accessorytypes">
    <id name="id" column="id" type="java.lang.Long" unsaved-value="0">
        <generator class="identity"></generator>
    </id>
    <properties name="CompositeId" >
        <property name="id" />
        <property name="Type" formula="'accessory'" />
    </properties>
    <map name="Name" table="ProductCode">
        <key property-ref="CompositeId" />
        <map-key column="Language" type="string" />
        <one-to-many class="ProductCode" />
    </map>
</class>

и

<class name="com.swissclick.wesco.web.model.ProductCode"
        table="ProductCode">
    <composite-id  class="com.swissclick.wesco.web.model.ProductCodeKey" mapped="true">
        <key-property name="Type"></key-property>
        <key-property name="id"></key-property>
    </composite-id>
    <property name="Language" type="string"></property>
    <property name="Value"></property>
</class>

но это тоже не работает, оно дает

org.hibernate.MappingException: collection foreign key mapping has wrong number of columns: AccessoryTypes.Name type: component[Id,Type]

, которая не выдает никакой полезной информации в Google.

есть идеи?

1 Ответ

2 голосов
/ 18 ноября 2009

Отредактировано . Так что я до сих пор не совсем понимаю структуру вашей таблицы - это то, что бросило меня, когда я написал первоначальный ответ.

Насколько я понимаю, ваша таблица Language выглядит примерно так:

Id -- this is a PK of entity (e.g. Accessory) this entry provides localization info for
Type -- string constant describing entity type (e.g. "accessory")
Language -- language code
Value -- actual localized string

Это выглядит правильно? Если это так, то возникает вопрос о том, как вы собираетесь локализовать несколько полей в одной и той же сущности. Разве у вас не должно быть хотя бы другого столбца, связывающего имя свойства (поля)?

В любом случае, <formula> действительно не поддерживается как часть <key> (я мог бы поклясться, что есть), поэтому ваши варианты здесь довольно ограничены:

  1. Используйте пользовательский загрузчик - это, вероятно, самый простой подход.
  2. Добавьте type в качестве фактического столбца в вашей таблице Accessory и отобразите его как часть составного идентификатора; затем вы можете отобразить карту Language, используя составной ключ. Должно работать, но довольно некрасиво.
  3. Переосмыслите свой подход. Вам действительно нужно каждый раз загружать карту языков? Похоже, что выполнение этого в виде отдельного запроса (или даже прямого get() с использованием соответствующего составного идентификатора) для текущего языка будет проще и (с соответствующей конфигурацией кэширования) намного быстрее.

Обновление Для уточнения по № 3 выше:

Прежде всего, позвольте мне прояснить это - я предполагаю, что ваши локализованные строки редактируются пользователем во время выполнения. Если это не так, я настоятельно рекомендую полностью отказаться от этой таблицы и вместо этого использовать пакеты ресурсов.

Я бы отобразил Language как отдельную сущность с type, id, language и (если вам нужно сделать это для нескольких свойств) property_name как части составного идентификатора. Фактически локализуемое свойство вашей сущности (например, ProductName на AccessoryType) будет временным. Затем вы можете вручную загрузить соответствующую локализованную строку для вашей сущности, выполнив что-то вроде:

AccessoryType accessory = ...;
Language language = (Language) session.get(Language.class,
 new LanguageKey("accessory", accessory.id, "en_US", "productName"));
accessory.setProductName(language.getValue());

Вы даже можете сделать это в слушателе событий , предполагая, что текущий выбранный язык доступен глобально (через глобальный или локальный вызов потока) - тогда это произойдет автоматически для всех ваших сущностей. Если языковая таблица достаточно мала, вы можете иметь Hibernate кешировать ее , и вы даже не будете подвергаться ударам базы данных по этому вопросу.

...