2010-06-11 1 views
1

Привет всем. Я понимаю, что это довольно длинный вопрос, но я бы очень признателен за любую помощь любого, кто имеет опыт работы с услугами RIA. Благодаря!Silverlight 4 + WCF RIA - Рекомендации по управлению услугами данных

Я работаю над приложением Silverlight 4, которое просматривает данные с сервера. Я относительно неопытен с RIA Services, поэтому я работал над задачами получения данных, которые мне нужны, для клиента, но каждый новый фрагмент, который я добавляю к головоломке, кажется все более проблематичным. Я чувствую, что мне не хватает некоторых базовых понятий здесь, и кажется, что я просто «взламываю» вещи, используя много времени, каждый из которых разбивает предыдущие, когда я пытаюсь их добавить. Я хотел бы получить отзывы разработчиков, имеющих опыт работы с службами RIA, чтобы выяснить, как сделать то, что я пытаюсь сделать. Позвольте мне рассказать, что я пытаюсь сделать:

Во-первых, данные. Источником этих данных является множество источников, в основном созданных совместно используемой библиотекой, которая считывает данные из нашей базы данных и предоставляет ее как POCOs (обычные объекты CLR). Я создаю свои собственные POCO для представления различных типов данных, которые мне нужно передать между сервером и клиентом.

DataA - Это приложение предназначено для просмотра определенного типа данных, позволяет вызывать DataA в режиме почти реального времени. Каждые 3 минуты клиент должен вытащить данные с сервера, всех новых DataA с момента последнего запроса данных.

DataB - Пользователи могут просматривать объекты DataA в приложении и могут выбрать один из них из списка, в котором отображаются дополнительные сведения об этом DataA. Я привожу эти дополнительные данные с сервера как DataB.

DataC - Одна из вещей, которые содержит DataB, - это история нескольких важных значений с течением времени. Я называю каждую точку данных этой истории объектом DataC, и каждый объект DataB содержит много DataC.

Модель данных - На стороне сервера, у меня есть один DomainService:

[EnableClientAccess] 
public class MyDomainService : DomainService 
{ 
    public IEnumerable<DataA> GetDataA(DateTime? startDate) 
    { 
     /*Pieces together the DataAs that have been created 
     since startDate, and returns them*/ 
    } 

    public DataB GetDataB(int dataAID) 
    { 
     /*Looks up the extended info for that dataAID, 
     constructs a new DataB with that DataA's data, 
     plus the extended info (with multiple DataCs in a 
     List<DataC> property on the DataB), and returns it*/ 
    } 

    //Not exactly sure why these are here, but I think it 
    //wouldn't compile without them for some reason? The data 
    //is entirely read-only, so I don't need to update. 
    public void UpdateDataA(DataA dataA) 
    { 
     throw new NotSupportedException(); 
    } 
    public void UpdateDataB(DataB dataB) 
    { 
     throw new NotSupportedException(); 
    } 
} 

Классы для DataA/B/C выглядеть следующим образом:

[KnownType(typeof(DataB))] 
public partial class DataA 
{ 
    [Key] 
    [DataMember] 
    public int DataAID { get; set; } 
    [DataMember] 
    public decimal MyDecimalA { get; set; } 
    [DataMember] 
    public string MyStringA { get; set; } 
    [DataMember] 
    public DataTime MyDateTimeA { get; set; } 
} 

public partial class DataB : DataA 
{ 
    [Key] 
    [DataMember] 
    public int DataAID { get; set; } 
    [DataMember] 
    public decimal MyDecimalB { get; set; } 
    [DataMember] 
    public string MyStringB { get; set; } 
    [Include] //I don't know which of these, if any, I need? 
    [Composition] 
    [Association("DataAToC","DataAID","DataAID")] 
    public List<DataC> DataCs { get; set; } 
} 

public partial class DataC 
{ 
    [Key] 
    [DataMember] 
    public int DataAID { get; set; } 
    [Key] 
    [DataMember] 
    public DateTime Timestamp { get; set; } 
    [DataMember] 
    public decimal MyHistoricDecimal { get; set; } 
} 

Я предполагаю, большой вопрос, который у меня есть здесь ... Должен ли я использовать объекты вместо POCOs? Правильно ли построены мои классы для правильной передачи данных? Должен ли я использовать методы Invoke вместо методов Query (Get) в DomainService?

На стороне клиента у меня возникает ряд проблем. Удивительно, но один из моих самых больших был нанизан. Я не ожидал, что с MyDomainContext будет много проблем с потоками. То, что я узнал, состоит в том, что вы только можете создать MyDomainContextObjects в потоке пользовательского интерфейса, все запросы, которые вы можете сделать, выполняются только асинхронно, и если вы попытаетесь сделать это синхронно, заблокировав вызывающий поток до тех пор, пока LoadOperation завершается, вы должны сделать это в фоновом потоке, так как он использует поток пользовательского интерфейса для выполнения запроса. Итак, вот что у меня есть.

Приложение должно отображать поток объектов DataA, распространяя каждый из них 3мин в течение следующих 3 минут (чтобы они в итоге отображались через 3 минуты после того, как они возникли, выглядящие как непрерывный поток, но их нужно загружать только через 3 минуты лопается). Для этого основная форма инициализирует, создает частный MyDomainContext и запускает фонового рабочего, который непрерывно петляет через некоторое время (true). В каждом цикле он проверяет, не осталось ли данных DataAs для отображения. Если это так, он отображает данные Data и Thread.Sleep() s до тех пор, пока не будет отображен следующий DataA.Если это из данных, он запрашивает больше, используя следующие методы:

public DataA[] GetDataAs(DateTime? startDate) 
{ 
    _loadOperationGetDataACompletion = new AutoResetEvent(false); 
    LoadOperation<DataA> loadOperationGetDataA = null; 

    loadOperationGetDataA = 
     _context.Load(_context.GetDataAQuery(startDate), 
     System.ServiceModel.DomainServices.Client.LoadBehavior.RefreshCurrent, false); 
    loadOperationGetDataA.Completed += new 
     EventHandler(loadOperationGetDataA_Completed); 

    _loadOperationGetDataACompletion.WaitOne(); 
    List<DataA> dataAs = new List<DataA>(); 
    foreach (var dataA in loadOperationGetDataA.Entities) 
     dataAs.Add(dataA); 

    return dataAs.ToArray(); 
} 

private static AutoResetEvent _loadOperationGetDataACompletion; 
private static void loadOperationGetDataA_Completed(object sender, EventArgs e) 
{ 
    _loadOperationGetDataACompletion.Set(); 
} 

кажется отчасти неуклюжим пытаются заставить его в быть синхронным, но так как это уже на фоне потока, я думаю, что это нормально ? До сих пор все на самом деле работает, как большая часть взлома, как кажется. Важно отметить, что если я попытаюсь запустить этот код в потоке пользовательского интерфейса, он блокируется, потому что он ожидает WaitOne() навсегда, блокируя поток, поэтому он не может сделать запрос загрузки на сервер.

Таким образом, как только данные будут отображаться, пользователи могут щелкнуть по одному, как только это будет, чтобы заполнить панель сведений полными данными DataB об этом объекте. Для этого у меня есть элемент управления пользовательскими панелями, который подписывается на событие выбора, которое у меня установлено, которое запускается при изменении выбора (в потоке пользовательского интерфейса). Я использую подобную технику там, чтобы получить объект DataB:

void SelectionService_SelectedDataAChanged(object sender, EventArgs e) 
{ 
    DataA dataA = /*Get the selected DataA*/; 

    MyDomainContext context = new MyDomainContext(); 
    var loadOperationGetDataB = 
     context.Load(context.GetDataBQuery(dataA.DataAID), 
     System.ServiceModel.DomainServices.Client.LoadBehavior.RefreshCurrent, false); 
    loadOperationGetDataB.Completed += new 
     EventHandler(loadOperationGetDataB_Completed);   
} 

private void loadOperationGetDataB_Completed(object sender, EventArgs e) 
{ 
    this.DataContext = 
     ((LoadOperation<DataB>)sender).Entities.SingleOrDefault(); 
} 

Опять же, это, кажется, своего рода Hacky, но это работает ... кроме как на DataB, что он загружает список DataCs пуст. Я пробовал всевозможные вещи там, и я не вижу, что я делаю неправильно, чтобы позволить DataCs спуститься с помощью DataB. Я готов сделать третий запрос для DataCs, но это еще больше кричит мне.

Мне кажется, что я сражаюсь с зерном здесь, как будто я делаю это совершенно непреднамеренно. Если кто-нибудь может оказать какую-либо помощь и указать, что я здесь делаю неправильно, я бы очень признателен!

Спасибо!

ответ

0

Должен сказать, что это кажется слишком сложным.

Если вы используете фреймворк сущности (который с версией 4 может генерировать POCO, если вам нужно) и Ria/LINQ, вы можете делать все это неявно с помощью ленивых команд загрузки, расширения и таблицы для каждого типа наследования.