【问题标题】:How to prevent the BreezeJS MetaData call being made multiple times如何防止多次调用 BreezeJS MetaData
【发布时间】:2023-04-01 13:08:01
【问题描述】:

我在 Angular2 中使用 BreezeJS,并注意到 MetaData 调用被多次调用。

我尝试通过在我的 BreezeDataService 的构造函数上调用 fetchMetadata() 来填充缓存,但这没有任何区别(它添加了另一个元数据调用)。

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

我认为这是由于主页加载时发出 5 次数据请求而导致的,每个请求都开始获取元数据,而无需等待现有的元数据调用完成。

您可以在www.quemesa.com 上使用网络工具查看问题:(前 5 个是 PReflight CORS 请求)

如何让代码等待任何现有的元数据调用完成而不是再次获取它?

使用代码更新:

@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);
    }

【问题讨论】:

    标签: breeze


    【解决方案1】:

    我和我的团队想出了解决这个问题的办法。我会尽力解释我们是如何做到的。我们的更改涉及对breeze.debug.js 的自定义。这个很重要!由于这涉及对 Breeze.js 的更改,因此如果您升级到新版本的 Breeze.js,请准备好再次进行更改!

    IndexedDB 比使用 localStorage 更具挑战性,我们这样做是因为我们在 webworker 中运行 Breeze - 而本地存储在 webworker 中不可用。只有 IndexedDB 是。

    1) 我们在 indexedDB 数据库中检查 proto.fetchMetadata 中的元数据。如果未找到(或不支持 indexedDB),则该方法回退到默认行为。

    2) 如果支持 IndexedDB,在 proto.ajaxMetaData 中的 Ajax 调用成功承诺中,我们将元数据写入 IndexedDB 数据库。

    仔细考虑您希望在 IndexedDB 中保留元数据缓存多长时间。是每期吗?每个新版本(可能包含新元数据)?您可能想要创建一个脚本来定期删除您的元数据缓存。我们有返回网站 DLL 的 DLL 版本信息的代码 - 我们将其与本地存储密钥进行比较以确定我们是否有新版本。这是限制最少的策略...它仅在新构建运行时清除缓存。

    但是,您可能希望在每次用户创建新会话时清除缓存。无论哪种方式,您用于每个 IndexedDB 条目的键都应该是唯一的 - 包含路由、数据上下文(如果这种重置很重要,还可以选择 sessionid。)

    您可以使用很长的字符串作为键。我建议创建一个包含键的所有唯一部分(路由、dllVersion、UserId)的 javascript 对象,然后将该对象转换为 JSON 字符串 - 并将该字符串用作 IndexedDB 键。

    即使您不应用元数据缓存,您至少应该在请求的元数据已加载时广播一个事件,如下所示:

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

    我们有一个包装类,它在元数据完全加载时广播这个事件。如果您不使用包装器,您可能希望将广播放在 proto.ajaxMetaData 中,或者如果您实现缓存,则在从 IndexedDB 缓存返回元数据之前立即广播它。

    在您的调用控制器中,使用它来监听该事件:

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

    这使您可以等到拥有元数据后再在控制器中发出第一个请求。

    祝你好运!

    【讨论】:

      【解决方案2】:

      您真的是说同一个EntityManager 实例发出多个元数据请求吗?我不记得是这样的。

      如果确实如此,(a) 我们应该解决这个问题 - 提交问题 - 并且 (b) 您可以在数据服务中解决它。

      您确实有数据服务,对吧?你的组件不应该直接与 EM 对话,而是通过一个中间服务来隔离组件与管理器的直接接触,并将这种交互抽象为某种语义。对于 Angular 应用程序,无论是否使用 Breeze,您都会在任何地方看到该建议。

      假设您遵循该建议,您可以在初始化步骤中获取元数据,保留承诺,并通过已解决的承诺链接所有后续调用。

      在您的应用中设置一个利用元数据承诺和任何其他预加载缓存的启动活动的初始化步骤可能会更简单。

      您还可以在服务器上预先缓存元数据,并通过 JavaScript 标记将其加载为 JSON 格式。 Breeze 文档中的示例。

      你有很多选择。

      最后的想法。你创建了多少EntityManagers?默认情况下,每个都将获取元数据。大多数人只需要一个,但有理由想要更多。如果您需要更多,请确保将一个指定为“master”并使用复制构造函数创建其他的。

      【讨论】:

      • 嗨 Ward,是的,我确实使用了数据服务 - 我添加了更多代码。我认为不起作用的部分(而且我不理解)是这个建议“假设您遵循该建议,您可以在初始化步骤中获取元数据,坚持承诺,并将所有后续调用链接到已解决承诺。”在 DataBreezeService 中,我声明了一个 entityManager:EntityManager - 我如何告诉所有使用它的调用等待,直到第一个 MetaData 调用完成?
      猜你喜欢
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-27
      相关资源
      最近更新 更多