簡體   English   中英

Silverlight 4 + WCF RIA-數據服務設計最佳實踐

[英]Silverlight 4 + WCF RIA - Data Service Design Best Practices

大家好。 我意識到這是一個相當長的問題,但是我非常感謝RIA服務經驗豐富的人員提供的任何幫助。 謝謝!

我正在使用Silverlight 4應用程序,該應用程序可以查看服務器中的數據。 我對RIA Services的經驗相對較少,因此一直在完成將我需要的數據提供給客戶端的任務,但是我添加到難題中的每個新問題似乎都越來越有問題。 我覺得我在這里缺少一些基本概念,似乎我只是在以浪費時間的方式“亂砍”片斷,每一個在嘗試添加它們時都破壞了前面的那些。 我很想獲得RIA服務經驗豐富的開發人員的反饋,以找出完成我要做的事情的預期方式。 讓我列出我想做的事情:

首先,數據。 這些數據的來源有很多種,主要是由一個共享庫創建的,該共享庫從我們的數據庫中讀取數據,並將其公開為POCO(普通的舊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; }
}

我想我這里有一個大問題是...我應該使用實體而不是POCO? 我的類是否構造正確,可以正確傳遞數據? 我應該在DomainService上使用Invoke方法而不是Query(Get)方法嗎?

在客戶端,我遇到許多問題。 令人驚訝的是,我最大的案例之一是線程。 我沒想到MyDomainContext會出現這么多線程問題。 我了解到的是,您似乎只能在UI線程上創建MyDomainContextObjects,您可以進行的所有查詢都是異步完成的,並且如果您嘗試通過阻塞調用線程來同步偽造它,直到LoadOperation完成后,您必須在后台線程上執行此操作,因為它使用UI線程進行查詢。 所以這就是我到目前為止所得到的。

該應用程序應顯示DataA對象的流,在接下來的3min內分散每個對象的3min塊(因此,它們在發生3分鍾后最終顯示,看起來像一個連續的流,但只需3分鍾即可下載)。 為此,主窗體將初始化,創建私有MyDomainContext並啟動后台工作程序,該工作程序會在while(true)中連續循環。 在每個循環上,它都會檢查是否有剩余的DataA可以顯示。 如果是這樣,它將顯示該Data和Thread.Sleep(),直到計划顯示下一個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();
}

試圖強制使其同步似乎有些笨拙,但是既然這已經在后台線程中了,我認為可以嗎? 到目前為止,一切實際上都可以正常進行,盡管看起來似乎很簡單。 重要的是要注意,如果我嘗試在UI線程上運行該代碼,則會鎖定該代碼,因為它會一直等待WaitOne()並鎖定該線程,因此無法向服務器發出Load請求。

因此,一旦顯示了數據,用戶就可以單擊它,以用有關該對象的完整DataB數據填充詳細信息窗格。 為此,我使用詳細信息窗格的用戶控件來訂閱我已設置的選擇事件,當選擇更改時(在UI線程上),該事件將被觸發。 我在那里使用類似的技術來獲取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上,DataC列表為空。 我在那里嘗試過各種方法,但我看不出我在做錯什么,以允許DataC與DataB一起使用。 我准備對DataC進行第三次查詢,但是這讓我感到更加討厭。

真的感覺就像我在這里與糧食作斗爭,就像我以一種完全意想不到的方式這樣做。 如果有人可以提供任何幫助,並指出我在這里做錯了什么,我將非常感謝!

謝謝!

我不得不說,這似乎有點過於復雜。

如果您使用實體框架(如果需要,則使用版本4可以生成POCO)和Ria / LINQ,則可以使用延遲加載,'expand'語句和每個類型繼承的表隱式完成所有這些工作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM