2013-02-10 12 views
5

Ich habe eine SPA-Anwendung (durandaljs), und ich habe eine bestimmte Route, wo ich die "ID" der Entität zuordnen, die ich abrufen möchte.Breezejs EntityManager MetadataStore und fetchEntityByKey

Die Vorlage ist "/ #/todoDetail /: id".

Zum Beispiel "/ #/todoDetail/232" oder "/ #/todoDetail/19".

Bei der Aktivierung von Viewmodel, bekomme ich die Route Info, so kann ich die ID greifen. Dann erstelle ich eine neue Instanz von brisejs EntityManager, um die Entity mit der angegebenen ID zu erhalten.

Das Problem ist, wenn ich Manager.fetchEntityByKey ("Todos", ID) aufrufen, hat der EntityManager noch nicht die Metadaten vom Server, so dass es wirft "Unable zu finden 'Typ mit dem Namen: Todos ".

Es funktioniert nur, wenn ich zuerst eine Abfrage für den Speicher ausführen (manager.executeQuery), vor dem Aufruf von FetchEntityByKey.

Ist dies ein erwartetes Verhalten oder ein Fehler? Gibt es eine Möglichkeit, die Metadaten während der Instantiierung von EntityManager automatisch zu reparieren?

Hinweis: Ich glaube, dass es in meinem Fall schwierig ist, einen gemeinsamen EntityManager zu verwenden, da ich dem Benutzer erlauben möchte, die Route direkt im Browser einzugeben.

EDIT:

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

Antwort

7

Sie haben über fetchMetadata gelernt: als eine vorübergehende Lösung, ich bin dies zu tun. Das ist wichtig. Wenn Ihre Anwendung ohne eine Abfrage beginnen kann, müssen Sie fetchMetadata verwenden und darauf warten, dass sie zurückkehrt, bevor Sie Operationen direkt im Cache ausführen können (z. B. nach einer Entität per Schlüssel im Cache suchen, bevor Sie auf eine Datenbankabfrage zurückgreifen)).

Aber ich spüre etwas anderes vor, weil Sie mehrere Manager erwähnt haben. Standardmäßig kennt ein neuer Manager die Metadaten von keinem anderen Manager. Aber wussten Sie, dass Sie können einen einzigen metadataStore unter Managern teilen? Sie können.

Was ich oft tue (und Sie sehen es in den Metadaten-Tests im DocCode-Beispiel), erhalten einen metadataStore für die Anwendung, schreiben eine EntityManager-Factory-Funktion, die neue Manager mit diesem metadataStore erstellt, und dann den Fabrik, wenn ich neue Manager mache ... wie es scheint, wenn Sie ein ViewModel hochfahren, um die TodoDetail zu überprüfen.

+0

gute suggestion, also werde ich entityManagers mit factories erstellen und globale Metadaten zwischen ihnen teilen. Übrigens, gibt es irgendwelche Chancen, die Brise zu verbessern, um diese Möglichkeit hinzuzufügen, wie eine globale Instanz von Metadatastore? Oder erzwinge dann EntityManager, Metadaten abzufragen, auch wenn ich nur fetchEntityByKey möchte, ohne eine vollständige Abfrage für den Service auszuführen? –

+0

Nicht sicher, was du meinst. Ich bin nicht so scharf auf Breeze-definierten Standard MetadataStore, aber das ist etwas, was Sie leicht für sich selbst erstellen können. Sie können einem MetadataStore mitteilen, dass er Metadaten abrufen soll (das ist natürlich asynchron), abgesehen von einer Abfrage (ich erwähnte dies in meiner Antwort). Sie können auch "EntityManager.createEmptyCopy" betrachten. Sie können dies auf Ihrem Master-EM aufrufen, um neue leere EMs zu erstellen, die vollständig konfiguriert sind. Der Rest Ihrer Factory-Methode importiert nur solche Entitäten (z. B. Referenzlisten), die Sie in der Kopie verwenden möchten. – Ward

2

Ausgehend von einem Silverlight Hintergrund, bei dem ich viele WCF RIA Services in Kombination mit Caliburn Micro verwendet habe, nutzte ich diesen Ansatz für die Integration von Breeze mit Durandal.

Ich habe einen Unterordner namens Dienste im App-Ordner der Anwendung erstellt. In diesem Ordner habe ich eine Javascript-Datei namens datacontext.js erstellt. Hier ist eine Teilmenge von meinem 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) 
     } 
    }; 
} 

Dann in Ihrem durandal Ansicht Modelle können Sie benötigen nur die Dienste/Datacontext.Zum Beispiel, hier ist ein Teil der Musteransicht Modell aus meiner 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; 
}); 

Dies ermöglicht es Ihnen nicht um die Initialisierung der Metadatenspeicher in jedem View-Modell zu kümmern, da sie alle an einem Ort durchgeführt wird.

+0

Ich habe auch einen Hintergrund auf Silverlight/Caliburn.Micro und WCF Ria Services. Wenn Sie Bundles von MVC verwenden, können Sie breeze.min.js in die gebündelten Skripts einfügen, und Sie müssen nicht "require" ("path/to/breeze") aufrufen. Siehe mein [Durandal Video] (http://www.youtube.com/watch?feature=player_embedded&v=in1M0vzg4mg). Mein Problem ist, dass ich Metadaten möchte, ohne zuerst eine Abfrage durchzuführen. Vielen Dank! –

+0

Ich denke, es hat für mich funktioniert, weil ich eine Abfrage verwendet habe, um die einzelne Entität zu erhalten. var query = breeze.EntityQuery.from ("Athletendetails") where ("Id", "==", id); – Bryant

+0

ja, funktionierte, weil, wenn Sie EntityQuery verwenden, Sie eine Abfrage ausführen, die Metadaten abruft, wenn der Manager nicht zuvor abgerufen wurde ... das Ergebnis der Abfrage wird ein Array von Entitäten sein, Sie müssen also auf den Nullindex zugreifen wie result.entities [0]. Es ist nicht der Fall von fetchEntityByKey(), das immer eine einzelne Entität oder null zurückgibt und optional Entität aus dem Cache zurückgeben kann, aber Metadaten für den Manager nicht abruft und eine Exception auslöst, wenn ich nicht manuell hole, wie ich es getan habe in der Frage. –

Verwandte Themen