Чтение и запись локализованных данных с помощью Entity
Glossary Item Box
Общие сведения
Начиная с версии 7.9.1, в метод Entity.FetchFromDB() добавлена возможность получения мультиязычных данных. Алгоритм выборки данных аналогичен алгоритму для EntitySchemaQuery (см. "Чтение локализованных данных с помощью EntitySchemaQuery"):
- Если текущая культура пользователя является основной для приложения, то объект получает данные из основной таблицы.
- Если текущая культура пользователя является дополнительной, то объект получает данные из таблицы локализации. Если в таблице локализации для текущей культуры пользователя нет данных, то возвращаются данные из основной таблицы.
Далее приведены примеры использования одной из перегрузок методов Entity.FetchFromDB() и Entity.Save(), а также анализ результатов их выполнения для пользователя с основной (русской) и дополнительной (английской) культурами. Эти методы могут быть использованы, например, в методах пользовательского сервиса (см. "Создание пользовательского конфигурационного сервиса").
Чтение данных
Пример кода получения данных из локализуемой колонки [Название] (Name) объекта схемы [Тип контрагента] (AccountType) на стороне сервера (C#):
// Пользовательское подключение. var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"]; // Получение схемы [Тип контрагента]. EntitySchema schema = userConnection.EntitySchemaManager.FindInstanceByName("AccountType"); // Создание экземпляра Entity (объекта). Entity entity = schema.CreateEntity(userConnection); // Коллекция имен колонок для выборки. List<string> columnNamesToFetch = new List<string> { "Name", "Description" }; // Получение данных для объекта, у которого значение колонки [Название] равно "Клиент". entity.FetchFromDB("Name", "Клиент", columnNamesToFetch); // Формирование и отправка ответа. var name = String.Format("Name: {0}", entity.GetTypedColumnValue<string>("Name")); return name;
Если содержащий этот код метод будет выполнен пользователем, у которого в профиле установлен язык по умолчанию, то в базу данных будет отправлен следующий запрос:
exec sp_executesql N' SELECT [AccountType].[Name] [Name], [AccountType].[Description] [Description] FROM [dbo].[AccountType] [AccountType] WITH(NOLOCK) WHERE [AccountType].[Name] = @P1',N'@P1 nvarchar(6)',@P1=N'Клиент'
В приведенном выше запросе в параметре в парметре @P1 указывается значение "Клиент", по которому определяется нужная запись таблицы базы данных.
Посмотреть запрос можно, используя SQL Server Profiler (рис. 1).
Рис. 1. — Профилирование запроса в базу данных с помощью SQL Server Profiler
Если метод будет выполнен пользователем, у которого в профиле установлен дополнительный язык (например, английский), то в базу данных будет отправлен следующий запрос:
exec sp_executesql N' SELECT ISNULL([SysAccountTypeLcz].[Name], [AccountType].[Name]) [Name], ISNULL([SysAccountTypeLcz].[Description], [AccountType].[Description]) [Description] FROM [dbo].[AccountType] [AccountType] WITH(NOLOCK) LEFT OUTER JOIN [dbo].[SysAccountTypeLcz] [SysAccountTypeLcz] WITH(NOLOCK) ON ([SysAccountTypeLcz].[RecordId] = [AccountType].[Id] AND [SysAccountTypeLcz].[SysCultureId] = @P2) WHERE [AccountType].[Name] = @P1',N'@P1 nvarchar(6),@P2 uniqueidentifier',@P1=N'Клиент',@P2='A5420246-0A8E-E111-84A3-00155D054C03'
В приведенном выше запросе в параметре @P1 указывается значение "Клиент", по которому определяется нужная запись основной таблицы базы данных. А в параметре @P2 — идентификатор дополнительной культуры из таблицы SysCulture, по которому будет определена соответствующая запись из таблицы локализации SysAcountTypeLcz.
Таким образом, значению переменной name для пользователя с русской культурой будет соответствовать "Клиент", а для пользователя с английской культурой — "Customer".
Сохранение локализованных данных
Для добавления и изменения локализованных данных предусмотрен метод Entity.SetColumnValue(). Данный метод может принимать как аргументы типа string, так и аргументы типа LocalizableString.
Сохранение локализованных данных с использованием string
При передаче аргумента типа string в метод Entity.SetColumnValue() используется следующий алгоритм сохранения:
- при создании новой записи пользователем, для которого установлена дополнительная культура, данные добавляются и в основную таблицу и в таблицу локализации для дополнительной культуры;
- при изменении уже существующего экземпляра Entity пользователем, для которого установлена дополнительная культура, результат сохраняется только в таблице локализации для дополнительной культуры;
- при создании или изменении Entity пользователем, для которого установлена основная культура, данные добавляются или обновляются в основной таблице объекта Entity.
Пример кода сохранения данных с использованием строкового аргумента:
var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"]; EntitySchema schema = userConnection.EntitySchemaManager.FindInstanceByName("AccountType"); Entity entity = schema.CreateEntity(userConnection); // Установка для колонок значений по умолчанию. entity.SetDefColumnValues(); // Установка значения для колонки [Название]. entity.SetColumnValue("Name", "Новый клиент"); // Сохранение. entity.Save(); var name = String.Format("Name: {0}", entity.GetTypedColumnValue<string>("Name")); return name;
При выполнении этого кода пользователем, в профиле которого установлен язык по умолчанию (русский), будет выполнен следующий запрос в базу данных:
exec sp_executesql N' INSERT INTO [dbo].[AccountType]([Id], [Name], [CreatedOn], [CreatedById], [ModifiedOn], [ModifiedById], [ProcessListeners], [Description]) VALUES(@P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)',N'@P1 uniqueidentifier,@P2 nvarchar(12),@P3 datetime2(7),@P4 uniqueidentifier,@P5 datetime2(7),@P6 uniqueidentifier,@P7 int,@P8 nvarchar(4000)',@P1='3A820BC8-006D-42B7-A472-E331FBD73E20',@P2=N'Новый клиент',@P3='2017-02-10 09:40:23.0909251',@P4='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P5='2017-02-10 09:40:23.0929256',@P6='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P7=0,@P8=N''
В приведенном выше запросе в параметре @P2 указывается значение "Новый клиент", которое сохраняется в основной таблице базы данных.
Если в профиле пользователя установлен дополнительный язык (например, английский), то для сохранения данных с использованием строкового аргумента необходимо выполнить следующий код:
var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"]; EntitySchema schema = userConnection.EntitySchemaManager.FindInstanceByName("AccountType"); Entity entity = schema.CreateEntity(userConnection); entity.SetDefColumnValues(); entity.SetColumnValue("Name", "New Customer"); entity.Save(); var name = String.Format("Name: {0}", entity.GetTypedColumnValue<string>("Name")); return name;
При выполнении этого кода будет выполнен такой же запрос в основную таблицу AccountType, как и для основной локализации, но в параметре @P2 будет указано значение "New Customer".
exec sp_executesql N' INSERT INTO [dbo].[AccountType]([Id], [Name], [CreatedOn], [CreatedById], [ModifiedOn], [ModifiedById], [ProcessListeners], [Description]) VALUES(@P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)',N'@P1 uniqueidentifier,@P2 nvarchar(12),@P3 datetime2(7),@P4 uniqueidentifier,@P5 datetime2(7),@P6 uniqueidentifier,@P7 int,@P8 nvarchar(4000)',@P1='94052A88-499D-4072-A28A-6771815446FD',@P2=N'New Customer',@P3='2017-02-10 10:07:00.3454424',@P4='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P5='2017-02-10 10:07:00.3454424',@P6='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P7=0,@P8=N''
Кроме того, будет выполнен запрос в таблицу локализации:
exec sp_executesql N' INSERT INTO [dbo].[SysAccountTypeLcz]([Id], [ModifiedOn], [RecordId], [SysCultureId], [Name]) VALUES(@P1, @P2, @P3, @P4, @P5)',N'@P1 uniqueidentifier,@P2 datetime2(7),@P3 uniqueidentifier,@P4 uniqueidentifier,@P5 nvarchar(12)',@P1='911A721A-0E5A-4CC3-B6D9-9E5FE85FEC64',@P2='2017-02-10 10:07:00.3664442',@P3='94052A88-499D-4072-A28A-6771815446FD',@P4='A5420246-0A8E-E111-84A3-00155D054C03',@P5=N'New Customer'
В приведенном запросе в параметре @P5 также указывается значение "New Customer".
Таким образом, в основную таблицу AccountType будет помещено значение, которое не соответствует основной локализации.
Для предотвращения подобных ситуаций необходимо использовать сохранение локализованных данных с использованием локализуемых строк.
Сохранение локализованных данных с использованием локализуемых строк
Пример кода сохранения данных с использованием аргумента — локолизуемой строки:
var userConnection = (UserConnection)HttpContext.Current.Session["UserConnection"]; EntitySchema schema = userConnection.EntitySchemaManager.FindInstanceByName("AccountType"); Entity entity = schema.CreateEntity(userConnection); entity.SetDefColumnValues(); // Создание локализуемой строки с локализованными значениями для разных культур. var localizableString = new LocalizableString(); localizableString.SetCultureValue(new CultureInfo("ru-RU"), "Новый клиент ru-RU"); localizableString.SetCultureValue(new CultureInfo("en-US"), "New Customer en-US"); // Установка значения колонки с помощью локализуемой строки. entity.SetColumnValue("Name", localizableString); entity.Save(); // Результат будет выведен в текущей культуре пользователя. var name = String.Format("Name: {0}", entity.GetTypedColumnValue<string>("Name")); return name;
При выполнении этого кода, независимо от установленного в профиле пользователя языка, в БД будут отправлены:
1. В основную таблицу — запрос со значением "Новый клиент ru-RU" в аргументе @P2:
exec sp_executesql N' INSERT INTO [dbo].[AccountType]([Id], [Name], [CreatedOn], [CreatedById], [ModifiedOn], [ModifiedById], [ProcessListeners], [Description]) VALUES(@P1, @P2, @P3, @P4, @P5, @P6, @P7, @P8)',N'@P1 uniqueidentifier,@P2 nvarchar(18),@P3 datetime2(7),@P4 uniqueidentifier,@P5 datetime2(7),@P6 uniqueidentifier,@P7 int,@P8 nvarchar(4000)',@P1='5AC81E4A-FCB2-4019-AE5B-0C485A5F65BD',@P2=N'Новый клиент ru-RU',@P3='2017-02-10 10:47:21.7471581',@P4='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P5='2017-02-10 10:47:21.7511578',@P6='410006E1-CA4E-4502-A9EC-E54D922D2C00',@P7=0,@P8=N''
2. В таблицу локализации — запрос со значением "New Customer en-US" в аргументе @P5:
exec sp_executesql N' INSERT INTO [dbo].[SysAccountTypeLcz]([Id], [ModifiedOn], [RecordId], [SysCultureId], [Name]) VALUES(@P1, @P2, @P3, @P4, @P5)',N'@P1 uniqueidentifier,@P2 datetime2(7),@P3 uniqueidentifier,@P4 uniqueidentifier,@P5 nvarchar(18)',@P1='6EC9C205-7F8B-455E-BC68-3D9AA6D7B7C0',@P2='2017-02-10 10:47:21.9272674',@P3='5AC81E4A-FCB2-4019-AE5B-0C485A5F65BD',@P4='A5420246-0A8E-E111-84A3-00155D054C03',@P5=N'New Customer en-US'
Если код будет выполнен пользователем, в профиле которого установлена дополнительная культура, а в локализуемой строке не будет указано значение для основной культуры, то в основную таблицу AccountType будет добавлена запись для дополнительной культуры пользователя.