IAsyncRepository или IObservableRepository для Silverlight 4 + службы данных WCF - PullRequest
4 голосов
/ 18 марта 2011

Обновление 2 : у @Enigmativity блестящий ответ. Я реализовал это в IObservableRepository<T>. Подробности в моем ответе ниже.


Вопрос: Поэтому я изменил большую часть вопроса (см. Историю изменений). Мне бы просто хотелось, чтобы кто-то прокомментировал / подтвердил / вырвал мой дизайн. =)

Поэтому, как правило, мои репо выглядят так:

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

Но когда дело доходит до Silverlight и служб данных WCF, они серьезно раздражают данные, связанные с запросами, со всей асинхронностью. Мне нужно сначала загрузить асинхронную родительскую сущность, а затем запросить ее асинхронную дочернюю сущность.

Итак, я придумал IAsyncRepository, я хотел бы знать, в порядке ли дизайн, можно ли его улучшить (и имеет ли смысл использовать Rx здесь?)

Для решения проблемы дочерних объектов я планирую загрузить все необходимые дочерние объекты перед вызовом обратного вызова.

Мой репо выглядит так:

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

Вы можете использовать репо следующим образом:

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

Что вы, ребята, думаете?

С уважением, Гидеон

Ответы [ 2 ]

4 голосов
/ 19 марта 2011

Просто быстрый ответ с манжеты.

Как насчет использования Реактивных расширений для .NET (Rx) ?

Затем вы можете определить свой репозиторий как:

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

Все возвращаемые наблюдаемые будут содержать одиночные значения, кроме GetAll, который будет иметь ноль или более.

Тип Unit - это void в мире Rx. Это просто способ не определять нестандартный интерфейс IObservable.

Затем вы бы запросили так:

IObservableRepository<Foo> repo = ...;

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

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

И отправить можно было бы так:

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

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

Все это основано на попытках сохранить методы репозитория как можно ближе к оригиналу, но может стоить рефакторинга со стороны Silverlight примерно так:

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

Отправить сейчас будет немного приятнее:

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

Как я уже сказал, с манжеты. : -)

3 голосов
/ 19 марта 2011

Слишком долго, чтобы обновить вопрос, поэтому я написал в качестве ответа.

Итак, я реализовал это так:

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

Некоторые примечания:

  • TContext необходимо для GetAll(), реализация будет иметь Entity Framework DataServiceContext, которая позволит вам сделать следующее:

    var foos = repo.GetAll(ts => ts.Where(t => t.Bar == "Hello"));
    //ts is a DataContext passed here by GetAll();
    
  • Методы, отмеченные //helpers просто вызовите другие методы, которые принимают массивы.
  • Фактический тип возврата для функций CRUD для WCF Data Services + Entity Framework - DataServiceResponse.Что я делаю, так это перебираю их и возвращаю коды статуса Http.Таким образом, возвращаемые значения для методов CRUD - это Http Status Codes.
  • При загрузке дочерних объектов я просто стремился загрузить их, выполнив это:

В принципе, я могу использовать это так:

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

Скажите мне, если мне нужно поднять фактическую реализацию здесь.

Любые комментарии по этому поводу были бы хорошо приняты=)

Спасибо

...