如何防止多次调用BreezeJS元数据

如何防止多次调用BreezeJS元数据,breeze,Breeze,我将BreezeJS与Angular2一起使用,并注意到元数据调用被多次调用 我试图通过在我的BreezeDataService的构造函数上调用fetchMetadata()来初始化缓存,但是这没有什么不同(它添加了另一个元数据调用) 我假设这是由主页加载时发出的5个数据请求引起的,每个请求都会在不等待现有元数据调用完成的情况下获取元数据 您可以看到网络工具的问题:(前5个是飞行前CORS请求) 我如何告诉代码等待任何现有元数据调用完成,而不是再次获取它 使用代码更新: @Injectable(

我将BreezeJS与Angular2一起使用,并注意到元数据调用被多次调用

我试图通过在我的BreezeDataService的构造函数上调用fetchMetadata()来初始化缓存,但是这没有什么不同(它添加了另一个元数据调用)

我假设这是由主页加载时发出的5个数据请求引起的,每个请求都会在不等待现有元数据调用完成的情况下获取元数据

您可以看到网络工具的问题:(前5个是飞行前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.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.ajaxmata中,或者如果实现缓存,则在从IndexedDB缓存返回元数据之前广播它

在呼叫控制器中,使用此命令侦听该事件:

$scope.$on('MetaDataLoadedServiceRoute', function (event, args) {
     $scope.setup();
});
这允许您在控制器中发出第一个请求之前等待元数据


祝你好运

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

如果真的是这样,(a)我们应该解决这个问题-提交一个问题-和(b)您可以在您的数据服务中解决它

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

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

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

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

所以你有很多选择


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

你好,沃德,是的,我确实使用了数据服务-我添加了更多的代码。我认为不起作用的部分(我不理解)是这样的建议:“假设您遵循了该建议,您可以在初始化步骤中获取元数据,保持承诺,并通过该已解决的承诺链接所有后续调用。”在DataBreezeService中,我声明了一个entityManager:entityManager-如何告诉所有使用它的调用等待第一个元数据调用完成?
$scope.$on('MetaDataLoadedServiceRoute', function (event, args) {
     $scope.setup();
});