4 Stimmen

IAsyncRepository oder IObservableRepository für silverlight 4 + WCF Data Services

Aktualisierung 2 : @Enigmativity hat eine brillante Antwort. Ich habe dies in eine IObservableRepository<T> . Einzelheiten in meiner Antwort unten.


Frage: Ich habe also das meiste an der Frage geändert (siehe Bearbeitungshistorie) und würde mich freuen, wenn jemand meinen Entwurf kommentiert/bestätigt/ausgekotzt hätte =)

Normalerweise sehen meine Repos also so aus:

public interface IRepository<T> where T : class
{
    T GetById(int id);
    IQueryable<T> GetAll();
    void InsertOnSubmit(T entity);
    void DeleteOnSubmit(T entity);
    int SubmitChanges();
}

Aber wenn es um Silverlight und WCF-Datendienste geht, wird die Abfrage von Daten mit all der Asynchronität sehr lästig. Ich muss zuerst die übergeordnete Entität asynchron laden und dann die untergeordneten Entitäten asynchron abfragen.

Also habe ich mir etwas einfallen lassen IAsyncRepository Ich würde gerne wissen, ob das Design in Ordnung ist, ob es verbessert werden kann (und ob es sinnvoll ist, Rx hier zu verwenden).

Um das Problem der untergeordneten Einheiten zu lösen, plane ich, alle erforderlich untergeordneten Entitäten vor dem Aufruf des Rückrufs.

Mein Repo sieht so aus:

public interface IAsyncRepository<T> where T : class
{
    void GetById(int id, Action<T> callback);
    void GetAllFromQuery(Func<MyEntities, IQueryable<Product>> funcquery,
                                             Action<IList<Calculator>> callback)
}

Sie könnten das Repo wie folgt verwenden:

productRepo.GetAllFromQuery(
    x => x.Products.Where(p => p.ID > 5),
    y => Assert.IsTrue(y.Count > 0)); //y is a IList<Product>

Was haltet ihr davon?

Herzliche Grüße, Gideon

4voto

Enigmativity Punkte 104081

Nur eine kurze Antwort aus dem Stegreif.

Wie wäre es mit der Verwendung des Reaktive Erweiterungen für .NET (Rx) ?

Sie könnten dann Ihr Repository wie folgt definieren:

public interface IObservableRepository<T> where T : class
{
    IObservable<T> GetById(int id);
    IObservable<T> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
    IObservable<Unit> InsertOnSubmit(T entity);
    IObservable<Unit> DeleteOnSubmit(T entity);
    IObservable<int> SubmitChanges();
}

Alle zurückgegebenen Observablen würden Einzelwerte enthalten, mit Ausnahme von GetAll die null oder mehr haben würden.

Les Unit Typ ist void in der Rx-Welt. Es ist nur eine Möglichkeit, ein Nicht-Generikum nicht definieren zu müssen IObservable Schnittstelle.

Die Abfrage würde dann so aussehen:

IObservableRepository<Foo> repo = ...;

var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));

foos.Subscribe(foo =>
{
    // Do something asynchronously with each `Foo`.
});

Und einreichen könnte man das so machen:

var submit =
    foos
        .Select(foo => repo.InsertOnSubmit(foo)).ToArray()
        .Select(s => repo.SubmitChanges());

submit.Subscribe(result =>
{
    // handle the asynchronous result of submit.
});

Dies alles basiert auf dem Versuch, die Repository-Methoden so nah wie möglich am Original zu halten, aber es könnte sich lohnen, die Silverlight-Seite zu überarbeiten, um so etwas zu erreichen:

public interface IObservableRepository<T> where T : class
{
    IObservable<T> GetById(int id);
    IObservable<T[]> GetAll(Func<IQueryable<T>, IQueryable<T>> query);
    IObservable<int> Submit(T[] insertsOrUpdates);
    IObservable<int> Submit(T[] insertsOrUpdates, T[] deletes);
}

Einreichen wäre jetzt ein bisschen netter:

repo.Submit(foos).Subscribe(result =>
{
    // Handle asynchronous result of submit;
});

Wie ich schon sagte, aus dem Stegreif :-)

3voto

gideon Punkte 19091

Zu lange, um die Frage zu aktualisieren, also habe ich sie als Antwort gepostet.

Also habe ich es so umgesetzt:

public interface IObservableRepository<T, TContext>
{
    IObservable<T> GetById(int id);
    IObservable<IList<T>> GetAll(Func<TContext, IQueryable<T>> funcquery);
    IObservable<int[]> SubmitInserts(IList<T> inserts);
    IObservable<int[]> SubmitDeletes(IList<T> deletes);
    IObservable<int[]> SubmitUpdates(IList<T> updates);
    //helpers
    IObservable<int> SubmitInsert(T entity);
    IObservable<int> SubmitDelete(T entity);
    IObservable<int> SubmitUpdate(T entity);
}

Einige Anmerkungen:

  • TContext wird benötigt für GetAll() wird die Implementierung über das Entity Framework DataServiceContext die Ihnen folgende Möglichkeiten bietet:

    var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));
    //ts is a DataContext passed here by GetAll();
  • Die markierten Methoden //helpers rufen Sie einfach die anderen Methoden auf, die Arrays annehmen.

  • Der eigentliche Rückgabetyp für CRUD-Funktionen für WCF Data Services+Entity Framework ist ein DataServiceResponse . Was ich tue, ist Schleife durch sie und geben Sie die Http-Status-Codes. Also die ints zurückgegeben für die CRUD-Methoden sind Http Status Codes.

  • Beim Laden von untergeordneten Einheiten muss ich nur eifrig geladen sie auf diese Weise:

    context.Products.Expand("Child").Expand("Child2");

Ich kann es im Grunde so verwenden:

productRepo.GetById(3).Subscribe(x => /* Do something with product x*/ );
productRepo.SubmitUpdate(product)
         .Subscribe(r => /*return code should be 204 (http) 201 for insert */);
//same for insert and delete

Sagen Sie mir, ob ich die tatsächliche Umsetzung hier veröffentlichen soll.

Über Kommentare dazu würde ich mich sehr freuen =)

Danke

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X