[英]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.