2013-02-10 9 views
5

Ho un'applicazione SPA (durandaljs), e ho un percorso specifico in cui mappare "id" dell'entità che voglio recuperare.Breezejs EntityManager MetadataStore e fetchEntityByKey

Il modello è "/ #/todoDetail /: id".

Ad esempio, "/ #/todoDetail/232" o "/ #/todoDetail/19".

Sulla funzione di attivazione di viewmodel, ottengo le informazioni sul percorso in modo da poter prendere l'id. Quindi creo una nuova istanza di breezejs EntityManager per ottenere l'entità con l'id specificato.

Il problema è quando chiamo manager.fetchEntityByKey ("Todos", id), l'EntityManager non ha ancora i metadati dal server, quindi genera un'eccezione "Impossibile trovare un 'Tipo' con il nome: Todos".

Funziona solo se prima eseguo una query sullo store (manager.executeQuery), prima di chiamare fetchEntityByKey.

È un comportamento previsto o un bug? Esiste un modo per auto-correggere i metadati durante l'istanziazione di EntityManager?

nota: Credo che sia difficile utilizzare un EntityManager condiviso nel mio caso, perché voglio consentire all'utente di digitare direttamente il percorso sul browser.

EDIT: Come soluzione temporanea, sto facendo questo:

BreezeService.prototype.get = function (id, callback) { 
    var self = this; 

    function queryFailed(error) { 
     app.showMessage(error.message); 
     callback({}); 
    } 

    /* first checking if metadatastore was already loaded */ 

    if (self.manager.metadataStore.isEmpty()) { 
     return self.manager.fetchMetadata() 
     .then(function (rawMetadata) { 
      return executeQuery(); 
     }).fail(queryFailed); 
    } else { 
     return executeQuery(); 
    } 

    /* Now I can fetch */ 
    function executeQuery() { 
     return self.manager.fetchEntityByKey(self.entityType, id, true) 
         .then(callback) 
         .fail(queryFailed); 
    } 
}; 

risposta

7

Hai imparato a conoscere fetchMetadata. È importante. Se l'applicazione può iniziare senza emettere una query, è necessario utilizzare fetchMetadata e attendere che venga restituita prima di poter eseguire qualsiasi operazione direttamente nella cache (ad esempio, il controllo di un'entità per chiave nella cache prima di tornare a una query di database).

Ma sento qualcos'altro in corso perché hai menzionato più gestori. Di default un nuovo manager non conosce i metadati di nessun altro gestore. Ma lo sapevi che puoi condividere un singolo metadataStore tra i gestori? Puoi.

Quello che faccio spesso (e lo vedrete nei test dei metadati nell'esempio DocCode), è ottenere un metadataStore per l'applicazione, scrivere una funzione di fabbrica EntityManager che crea nuovi gestori con quel metadataStore e quindi utilizzare il fabbrica ogni volta che creo nuovi manager ... come sembra che tu stia facendo quando fai girare un ViewModel per rivedere TodoDetail.

+0

buona congestione, quindi creerò entityManager con le fabbriche, condividendo metadati globali tra di loro. A proposito, ci sono possibilità di migliorare la brezza per aggiungere questa funzione, come un'istanza globale di metadatastore? Oppure forzare l'entitymanager a interrogare i metadati anche se desidero solo recuperare FeturnByKey, senza eseguire una query completa contro il servizio? –

+0

Non sai cosa intendi. Non sono così entusiasta del MetadataStore di default definito da Breeze, ma è qualcosa che potresti facilmente creare da solo. Si può dire a MetadataStore di recuperare i dati metadati (ovviamente asincrona) a prescindere da una query (l'ho menzionata nella mia risposta). Si potrebbe anche guardare a 'EntityManager.createEmptyCopy'. Puoi chiamarlo sul tuo master EM per creare nuovi EM vuoti completamente configurati; il resto del tuo metodo factory importerebbe dal master solo quelle entità (ad es. elenchi di riferimento) che desideri nella copia. – Ward

2

Provenendo da uno sfondo Silverlight in cui ho utilizzato molti servizi RIA WCF combinati con Caliburn Micro, ho utilizzato questo approccio per l'integrazione di Breeze con Durandal.

Ho creato una sottocartella denominata servizi nella cartella App dell'applicazione. In quella cartella ho creato un file javascript chiamato datacontext.js. Qui è un sottoinsieme del mio DataContext:

define(function (require) { 

    var breeze = require('lib/breeze'); // path to breeze 
    var app = require('durandal/app'); // path to durandal 

    breeze.NamingConvention.camelCase.setAsDefault(); 

    // service name is route to the Web API controller 
    var serviceName = 'api/TeamData', 

    // manager is the service gateway and cache holder 
    manager = new breeze.EntityManager(serviceName), 

    store = manager.metadataStore; 

    function queryFailed(error) { 
     app.showMessage("Query failed: " + error.message); 
    } 

    // constructor overrides here 

    // included one example query here 
    return datacontext = { 
     getSponsors: function (queryCompleted) { 
      var query = breeze.EntityQuery.from("Sponsors"); 
      return manager 
       .executeQuery(query) 
       .then(queryCompleted) 
       .fail(queryFailed) 
     } 
    }; 
} 

Poi nei modelli vista Durandal si può semplicemente richiedere i servizi/DataContext.Ad esempio, qui è parte di una vista del modello di esempio dalla mia app:

define(function (require) { 

    var datacontext = require('services/datacontext'); 

    var ctor = function() { 
     this.displayName = 'Sponsors', 
     this.sponsors = ko.observable(false) 
    }; 

    ctor.prototype.activate = function() { 
     var that = this; 
     return datacontext.getSponsors(function (data) { that.sponsors(data.results) }); 
    } 

    return ctor; 
}); 

Questo vi permetterà di non preoccuparsi per l'inizializzazione dei metadati in ogni modello di vista dal momento che è tutto fatto in un unico luogo.

+0

Ho anche uno sfondo su Silverlight/Caliburn.Micro e WCF Ria Services. In realtà, se si utilizzano i bundle di MVC, è possibile includere breeze.min.js negli script in bundle e non è necessario chiamare require ('path/to/breeze'). Vedi il mio [video durandale] (http://www.youtube.com/watch?feature=player_embedded&v=in1M0vzg4mg). Il mio problema è che voglio i metadati senza prima fare una query. Grazie! –

+0

Suppongo che abbia funzionato per me perché stavo usando una query per ottenere la singola entità. var query = breeze.EntityQuery.from ("AthleteDetails"). where ("Id", "==", id); – Bryant

+0

sì, ha funzionato perché se si utilizza EntityQuery, si sta eseguendo una query che recupera i metadati se il gestore non è stato recuperato prima ... il risultato della query sarà una matrice di entità, quindi è necessario accedervi per l'indice zero come risultato.entità [0]. Non è il caso di fetchEntityByKey() che restituisce sempre una singola entità o null, e può facoltativamente restituire entità dalla cache se lo si desidera, ma non recupera i metadati per il gestore e genera un'eccezione se non recupero manualmente, come ho fatto io nella domanda. –

Problemi correlati