2016-12-26 8 views
2

Я использую BreezeJS с Angular2 и заметил, что вызов MetaData вызывается несколько раз.Как предотвратить звонок BreezeJS MetaData, сделанный несколько раз

Я попытался настроить кеш, вызвав fetchMetadata() в конструкторе моего BreezeDataService, однако это не имеет никакого значения (он добавляет еще один вызов метаданных).

this.entityManager.fetchMetadata().then(function() { console.log('entityManager.fetchMetadata finished'); }); 

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

Вы можете увидеть проблему на www.quemesa.com с инструментами СЕТЕЙ: enter image description here (Первый 5 являются запросами Предполетного CORS)

Как я могу сказать код, чтобы ждать любого существующего вызова метаданных для завершения вместо извлечения его еще раз?

UPDATE с кодом:

@Injectable() 
export class DataBreezeService { 
    public isSaving: boolean = false; 
    public entityManager: EntityManager; 

    constructor(private spinnerService: SpinnerService, private loggerService: LoggerService) { 
     this.entityManager = new EntityManager(environment.webApiServiceUrl); 
     this.entityManager.metadataStore.namingConvention = NamingConvention.camelCase; 

     this.entityManager.fetchMetadata().then(() => this.loggerService.info('entityManager.fetchMetadata finished')); 
    } 

    public executeQueryArray(query: EntityQuery) { 
     return this.entityManager.executeQuery(query) 
      .then((queryResult: QueryResult) => this.successArrayDataLoad(queryResult)) 
      .catch((error) => this.errorDataLoad(error))  
    } 

, а затем у меня есть различные службы сущностей, которые используют DataBreezeService:

@Injectable() 
export class BookingService { 
    constructor(private dataBreezeService: DataBreezeService, private loggerService: LoggerService) { 
    } 

    public getBookingsForUser(userId: number, forceServerCall: boolean = false) { 
     this.dataBreezeService.initialiseQuery('getBookingsForUser', [userId], forceServerCall); 

     let query = new EntityQuery() 
      .from("bookings") 
      .where("createdByUserId", "==", userId) 
      .where("visibilityId", "==", Status.Active) //booking is active 
      .toType('Booking') 
      .expand('createdByUser, restaurant, restaurant.suburb, restaurantScheduleDiscount, rating') 
      .orderBy("bookingDate Desc") 
      .inlineCount(); //return total 

     return this.dataBreezeService.executeQueryArray(query); 
    } 

ответ

0

Моя команда и я придумал решение для этой проблемы. Я сделаю все возможное, чтобы объяснить, как мы это сделали. Наши изменения включали настройки для breeze.debug.js. Это важно! Поскольку это связано с изменениями в Breeze.js, будьте готовы внести изменения снова, если вы перейдете на новую версию Breeze.js!

IndexedDB является более сложным, чем использование localStorage, мы делаем это, потому что мы запускаем Breeze в webworker - и локальное хранилище недоступно внутри веб-работников. Только IndexedDB.

1) Мы проверяем базу данных indexedDB для метаданных в файле proto.fetchMetadata. Если он не найден (или indexedDB не поддерживается), метод возвращается к поведению по умолчанию.

2) Если IndexedDB поддерживается, в обещании успеха вызова Ajax в proto.ajaxMetaData мы записываем метаданные в базу данных IndexedDB.

Подумайте, как долго вы хотите сохранить кеш метаданных в IndexedDB. Это каждый сеанс? Каждая новая сборка (которая может содержать новые метаданные)? Возможно, вы захотите создать сценарий, который периодически удаляет ваш кеш метаданных. У нас есть код, который возвращает информацию о DLL-версии DLL веб-сайта, которую мы сравниваем с локальным ключом хранилища, чтобы определить, есть ли у нас новая сборка. Это наименее ограничивающая политика ... она только очищает кеш, если выполняется новая сборка.

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

Вы можете использовать очень длинные строки в качестве ключей. Я рекомендую создать объект javascript, содержащий все уникальные части ключа (route, dllVersion, UserId), а затем преобразовать объект в строку JSON и использовать эту строку в качестве ключа IndexedDB.

Даже если вы не применять кэширование метаданных, вы должны по крайней мере транслировать событие, когда метаданные для вашего запроса загружен, например:

$rootScope.$broadcast('MetaDataLoaded' + serviceRoute, dataContext); 

У нас есть класс-обертку, который распространял этот когда метаданные полностью загружены. Если вы не используете обертку, вы, вероятно, захотите разместить трансляцию в файле proto.ajaxMetaData, или если вы реализуете кеширование, передайте ее прямо перед возвратом метаданных из вашего кеша IndexedDB.

В контроллере вызова, используйте это для прослушивания этого события:

$scope.$on('MetaDataLoadedServiceRoute', function (event, args) { 
    $scope.setup(); 
}); 

Это позволяет ждать, пока вы не метаданные прежде, чем сделать свой первый запрос в контроллере.

Удачи вам!

0

Вы действительно говорите, что тот же экземпляр EntityManager выдает более одного запроса метаданных? Я не помню, чтобы это было так.

Если это действительно так, (а) мы должны исправить это - зарегистрировать проблему - и (b) вы можете обходить ее в своей службе данных.

У вас есть служба передачи данных, не так ли? Ваши компоненты никогда не должны разговаривать с EM напрямую, а через промежуточную службу, которая изолирует компоненты от прямого контакта с менеджером и абстрагирует это взаимодействие во что-то семантичное. Вы увидите этот совет всюду для Угловых приложений, будь то Бриз или нет.

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

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

Вы также можете предварительно кэшировать метаданные на сервере и загружать их как JSON-ish через тег JavaScript. Примеры этого приведены в документах Бриза.

Так много вариантов для вас.

Последнее рассматривается. Сколько EntityManager s вы создаете? По умолчанию каждый будет извлекать метаданные. Большинство людей только нуждаются в одном, но есть причины, чтобы хотеть большего. Если вам нужно больше, убедитесь, что вы назначили его «мастером» и используйте конструктор копирования для создания других.

+0

Hi Ward, да, я пользовался услугами передачи данных. Я добавил еще несколько кодов. Я думаю, что часть, которая не работает (и что я не понимаю), - это предложение «Предполагая, что вы следуете этому совету, вы можете получать метаданные на этапе инициализации, придерживаться обещания и связывать все последующие вызовы с помощью этого разрешения обещаю «. В DataBreezeService я объявляю entityManager: EntityManager - как я могу рассказать обо всех вызовах, которые используют его для WAIT, пока не завершится первый вызов MetaData? – Rodney