2011年3月30日 星期三

更新EDM之後,資料來源未同步更新

當我們在開發Silverlight 的RIA Services時,難免遇到需要更改資料庫的時候,當新增欄位或表格的時候,除了需要更新EDM(Entity Data Model)之外,相關的部分也需要更新。

image

當使用RIA Services免不期然的需要使用到"網域服務類別",這裡面的資料是不會依據EDM的更新而做更新的,需要我們自己加入新的欄位或表格,更新需要更新的部分。

需要更新的類別通常會是xxxDomainService.cs和xxxDomainService.metadata.cs這兩個檔案。更新檔案後,整個Solution需要重新建置,以使資料來源能夠取得新的中繼資料。

image

2011年3月29日 星期二

[Silverlight]WCF RIA Services與WCF Services的衝突

問題:

  • 當在Solution中同時使用WCF RIA Services(網域服務類別)與WCF Services(啟用Silverlight的WCF服務)時,VS2010會在建置Project時Crash,其主要原因是MSBuild的設置錯誤所致。

解決方式:

  • 將C:\Program Files\MSBuild\Microsoft\Silverlight\v4.0\Microsoft.VisualStudio.ServiceModel.targets 刪除,
  • 或是將以上檔案中的ClientReferenceAssemblies="@(RiaClientCodeGenClientReferenceAssemblies)" 這一行刪除都可以。

注意:

  • 解決方式必須要在關閉VS2010的狀態下進行才會有效,改完後即可正常建置。

參考資料:

2011年3月28日 星期一

LINQ的join指令探討

 

架構

  1: from u in member.Where(u => u.LoginName == userName)
  2: join r in userRole on u.MemberId equals r.UserId
  3: join s in role on r.RoleId equals s.RoleId
  4: select s.RoleName

注意這裡第2行與第3行裡面的equals指令,其左右兩邊的敘述,並不可以對調


這牽涉到join的宣告方式,我們看一下System.Linq.Enumerable裡面是這麼宣告的:


public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(


this IEnumerable<TOuter> outer,


 IEnumerable<TInner> inner,


 Func<TOuter, TKey> outerKeySelector,


 Func<TInner, TKey> innerKeySelector,


Func<TOuter, TInner, TResult> resultSelector)


看到這邊我們就知道為什麼了,一切都是函式簽章搞的鬼啊。果真LINQ不僅僅是SQL的進化而已。

2011年3月23日 星期三

Silverlight的RIA Services同步技術

 

image

需求:使用者可以選擇一般會員或創業會員,甚至同時選擇兩者,在按下確定,並處理完畢後,顯示訊息給使用者。

           預期的執行緒的執行順序是:一般會員=>創業會員=>提示訊息

架構
  1:         
  2: private MemberDomainContext dc = new MemberDomainContext();
  3: private Member member;
  4: //事件控制
  5: private static AutoResetEvent evt = new AutoResetEvent(false);

  1: //我們先用AutoResetEvent.WaitOne()來把還不需要執行的執行緒先擋住,先把資源留給要用的執行緒                
  2:                 if (GeneralCheckBox.IsChecked == true)
  3:                 {
  4:                     new Thread(new ThreadStart(() =>
  5:                     {
  6:                         LoadOperation<Role> loadOp = dc.Load(dc.GetRoleByRoleNameQuery("一般會員"), RoleLoadedCallback, null);
  7:                     })).Start();
  8:                 }
  9: 
 10:                 if (BusinessCheckBox.IsChecked == true)
 11:                 {
 12:                     new Thread(new ThreadStart(() =>
 13:                     {
 14:                         //等待一般會員的執行緒
 15:                         if ((options & RoleOptions.General) == RoleOptions.General)
 16:                             evt.WaitOne(); //擋住,不讓下面的敘述執行
 17: 
 18:                         LoadOperation<Role> loadOp = dc.Load(dc.GetRoleByRoleNameQuery("創業會員"), RoleLoadedCallback, null);
 19:                     })).Start();
 20:                 }
 21: 
 22:                 new Thread(new ThreadStart(() =>
 23:                 {
 24:                     //等待一般會員或創業會員的執行緒
 25:                     evt.WaitOne();
 26: 
 27:                     this.Dispatcher.BeginInvoke(() =>
 28:                     {
 29:                         MessageBox.Show("加入會員成功", "會員加入成功", MessageBoxButton.OK);
 30:                     });
 31: 
 32:                 })).Start();
  1: //對資料庫作變更的動作(非同步執行,這時候還沒有執行完成)   
  2:         private void RoleLoadedCallback(LoadOperation<Role> Op)
  3:         {
  4:             int roleId = Op.Entities.Select(r => r.RoleId).FirstOrDefault();
  5: 
  6:             UserRole ur = new UserRole();
  7: 
  8:             ur.RoleId = roleId;
  9:             ur.UserId = member.MemberId;
 10:             dc.UserRoles.Add(ur);
 11: //不使用AutoResetEvent的話,SubmitChanges會有衝突
 12:             dc.SubmitChanges(OnUserRoleSubmitCompleted, null);
 13:         }
  1: //變更資料庫完成,利用AutoResetEvent.Set()通知AutoResetEvent物件,可以把資源給別的執行緒使用了        
  2:         private void OnUserRoleSubmitCompleted(SubmitOperation so)
  3:         {
  4:             if (so.HasError)
  5:             {
  6:                 MessageBox.Show(string.Format("Submit Failed: {0}", so.Error.Message));                
  7:                 so.MarkErrorAsHandled();
  8:             }
  9:             evt.Set();
 10:             Thread.Sleep(1);
 11:         }

Enum與FlagAttribute的應用

需求:可以讓使用者選取一般會員或創業會員,也可以同時選取一般會員與創業會員。

image

 
  1: //定義玉預設值部分
  2:         [Flags]
  3:         public enum RoleOptions
  4:         {
  5:             General = 0x01,  //0001, 一般會員
  6:             Business = 0x02, //0010, 創業會員
  7:         }
  8:         RoleOptions options = 0;
  1:         //當一般會員核取事件發生時,設定一般會員旗標
  2:         private void GeneralCheckBox_Checked(object sender, RoutedEventArgs e)
  3:         {
  4:             options |= RoleOptions.General;
  5:         }
  6:         
  7:         //當創業會員和曲事件發生時,設定創業會員旗標 
  8:         private void BusinessCheckBox_Checked(object sender, RoutedEventArgs e)
  9:         {
 10:             options |= RoleOptions.Business;
 11:         }
 12: 
 13:         //當一般會員取消核取時,移除一般會員旗標 
 14:         private void GeneralCheckBox_Unchecked(object sender, RoutedEventArgs e)
 15:         {
 16:             options ^= RoleOptions.General;
 17:         }
 18: 
 19:         //當創業會員取消核取時,移除創業會員旗標
 20:         private void BusinessCheckBox_Unchecked(object sender, RoutedEventArgs e)
 21:         {
 22:             options ^= RoleOptions.Business;
 23:         }
  1: //如果是一般會員的話,我們可以做的事
  2: 
  3: if ((options & RoleOptions.General) == RoleOptions.General)
  4: 
  5: //如果是創業會員的話,我們可以做的事
  6: 
  7: if ((options & RoleOptions.Business) == RoleOptions.Business)
參考資料