Каков наилучший способ реализации многоязычных доменных объектов с помощью NHibernate? - PullRequest
4 голосов
/ 19 мая 2010

Каков наилучший способ проектирования объектов Домена, которые могут иметь многоязычные поля. Примером может служить класс Product с описанием на нескольких языках.

Я нашел несколько ссылок, но не смог решить, какой из них лучший.

  1. http://fabiomaulo.blogspot.com/2009/06/localized-property-with-nhibernate.html
    (Это хранит все локализованные языковые данные в одном поле. Может быть проблемой, если мы запросим из Sql)

  2. http://ayende.com/Blog/archive/2006/12/26/LocalizingNHibernateContextualParameters.aspx
    (У этого в начале есть предупреждение, что это хак и больше не поддерживается)

  3. http://www.webdevbros.net/2009/06/24/create-a-multi-languaged-domain-model-with-nhibernate-and-c/
    (Это не описывает, как многоязычные данные будут структурированы в базе данных.)

Любой, кто имеет опыт использования NHibernate с многоязычными данными. Есть ли лучший способ?

Ответы [ 4 ]

2 голосов
/ 02 июня 2010

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

dictionary
----------
ID: int - identity
name: nvarchar(255)

phrase
------
dictionary_id:int  (fkey dictionary.ID)
culture_id:int     (LCID)
phrase:nvarchar(255)  - this is the default size - seems too small

Согласно этой записи в блоге , 255 - это длина строки по умолчанию для значений String. Чтобы преодолеть короткую длину строки в тексте фразы, вы можете изменить тег <element> на

<element column="phrase" type="String" length="4001"></element>

Чтобы использовать это в модели вашего домена, вы добавляете свойство PhraseDictionary к вашей сущности, где вы хотите перевести текст. Например. свойство title или свойство decription.

Я думаю, что в статье описан отличный подход, и я хотел бы перейти за.

РЕДАКТИРОВАТЬ: в ответ на комментарии, сделать длину меньше, чем 4001, если вы знаете, что абсолютный максимальный размер меньше, чем это, так как обычно это будет быстрее. Кроме того, NHibernate будет лениво извлекать коллекцию, но может извлекать все элементы одновременно. Вы можете профилировать, чтобы определить, влияет ли это на производительность. (Если у вас есть только несколько языков, то я сомневаюсь, что вы увидите разницу.) Если у вас много языков (скажем, 50+), возможно, стоит создать пользовательские свойства для извлечения локализованного текста. Они будут выдавать запросы для извлечения необходимого текста. Что еще более важно, вы можете получить весь текст для данного объекта в одном запросе, а не каждое локализованное текстовое свойство как отдельный запрос.

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

1 голос
/ 07 июня 2010

Включают ли ваши требования объекты домена, фактически имеющие многоязычные свойства в одном и том же объекте? И, если это так, это неограниченные переводы, хранящиеся в объекте (скажем, в коллекции - в этом случае я бы сказал, что это должно быть так же, как в любой коллекции master / detail или parent / child) или фиксированные переводы, в которых если языки (и, следовательно, отображение результатов сохраненного процесса или чего-либо еще) должны быть определены статически в любом случае?

Во многих интернационализированных приложениях, над которыми я работал, данные были только на одном языке - имена клиентов, названия продуктов (не было смысла сопоставлять даже идентичные продукты, используемые в одной стране, с продуктами в другой, все они имели разных дистрибьюторов и разные артикулы и, конечно же, локализованные цены). Интерфейс также был только на одном языке (одновременно). Таким образом, все доменные объекты требовали только один язык за раз. Таким образом, язык перевода будет определен при создании объекта.

У нас были переводческие пользовательские интерфейсы, которые позволяли пользователям обновлять переведенные тексты, но для них требовалось только два языка одновременно (локальный и по умолчанию). Я вижу, что это ближе всего к тому, о чем ты говоришь. Я предполагаю, что у вас будут дочерние коллекции для каждого переводимого свойства со всеми возможными переводами в коллекции. Это, вероятно, будет ближе всего ко второму решению в третьей статье, которую вы связали. Конечно, на этом этапе вам также необходимо узнать, хотите ли вы загружать с нетерпением или бездействием и т. Д.

1 голос
/ 07 июня 2010

С точки зрения строго ориентированной на базу данных SQL Server у вас должна быть одна таблица со всеми базовыми данными (ключ записи, даты, числа и т. Д.) И одна таблица со всеми переводимыми строковыми данными. Позвольте вызвать две таблицы Base и Base_Description.

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

Таблица Base_Description связана с базовой таблицей, но также содержит значение для выбора языка, на котором находятся данные. В моих проектах мы используем столбец langid из sys.languages ​​, потому что мы можем установить язык соединения с , а затем захватить его с @@ LANGID для большинства операций.

В нашем тестировании мы обнаружили, что это значительно быстрее, чем наличие нескольких полей для каждого языка, это также позволяет легче добавлять другие языки. Мы также используем полнотекстовую индексацию SQL Server, и она полностью работает с этим методом. Вы должны индексировать на нейтральном языке, а затем выбрать язык для поиска во время выполнения (также фильтрация по столбцу LangID в Base_Description).

1 голос
/ 04 июня 2010

У меня есть опыт работы только с Hibernate, но поскольку nHibernate очень похож:

Один из вариантов - определить тип компонента MultilingualString с элементами для каждого языка (предполагается, что набор языков известен во время кодирования). Этот тип также удобен для размещения получателя строки по идентификатору языка.

class MultiLingualString {
    String english;
    String chinese;
    String klingon;

    String forLanguage(Language lang) {
        switch (lang) {
            // you can guess what goes here
        }
    }
}

В результате строки для всех языков сохраняются в отдельных столбцах базы данных, в то время как представление в мире объектов сохраняет тонкую гранулярность.

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

Если вы много делаете, написание UserType может стоить этого.

...