2010-07-19 55 views
0

我有一個實體框架,在客戶和聯繫人之間具有多對多關係。通過RIA域服務在xaml中進行數據綁定的問題

我已經生成了一個域服務類並手動添加了以下方法。

public Customer GetCustomerById(int Id) 
{ 
    return this.ObjectContext.Customer.Include("Contacts").SingleOrDefault(s => s.Id == Id); 
} 

我現在要創建一個頁面,顯示客戶的詳細信息以及與該客戶關聯的聯繫人列表。

我在customerdetails.xaml的代碼隱藏中讀取傳入頁面的Id參數。

public int CustomerId 
{ 
    get { return (int)this.GetValue(CustomerIdProperty); } 
    set { this.SetValue(CustomerIdProperty, value); } 
} 

public static DependencyProperty CustomerIdProperty = DependencyProperty.Register("CustomerId", typeof(int), typeof(CustomerDetails), new PropertyMetadata(0)); 

// Executes when the user navigates to this page. 
protected override void OnNavigatedTo(NavigationEventArgs e) 
{ 
    if (this.NavigationContext.QueryString.ContainsKey("Id")) 
    { 
     CustomerId = Convert.ToInt32(this.NavigationContext.QueryString["Id"]); 
    } 
} 

我用下面的XAML頁面:

<Grid x:Name="LayoutRoot" DataContext="{Binding ElementName=customerByIdSource, Path=Data}"> 
    <riaControls:DomainDataSource Name="customerByIdSource" AutoLoad="True" QueryName="GetCustomerById"> 
     <riaControls:DomainDataSource.QueryParameters> 
      <riaControls:Parameter ParameterName="Id" Value="{Binding ElementName=CustomerDetailsPage, Path=CustomerId}" /> 
     </riaControls:DomainDataSource.QueryParameters> 
     <riaControls:DomainDataSource.DomainContext> 
      <sprint:Customer2DomainContext/> 
     </riaControls:DomainDataSource.DomainContext> 
    </riaControls:DomainDataSource> 
    <StackPanel x:Name="CustomerInfo" Orientation="Vertical"> 
     <StackPanel Orientation="Horizontal" Margin="3,3,3,3"> 
      <TextBlock Text="Id"/> 
      <TextBox x:Name="idTextBox" Text="{Binding Id}" Width="160"/> 
     </StackPanel> 
     <StackPanel Orientation="Horizontal" Margin="3,3,3,3"> 
      <TextBlock Text="Name"/> 
      <TextBox x:Name="nameTextBox" Text="{Binding Name}" Width="160"/> 
     </StackPanel> 

     <ListBox ItemsSource="{Binding Contact}" DisplayMemberPath="FullName" Height="100" /> 
    </StackPanel> 
</Grid> 

當我做這個文本框通過綁定得到很好的填充,但列表框保留爲空。

兩個問題:

  1. 我可以採用某種指定返回 類型GetCustomerById查詢, 所以我能看到的名字,當我 指定通過 性能GUI的約束力?

  2. 我在做什麼 這裏錯了嗎?爲什麼不是我的ListBox 填充?我是否正確地使用這種方法,還是需要在代碼隱藏中設置列表框的數據綁定?如果是這樣,怎麼樣?我還沒有找到如何以編程方式通過域數據源訪問聯繫人屬性。

我使用Silverlight和Entity Framework 4

回答

0

我已經找到了答案,我的問題2:

的關聯屬性Contacts不包括在所生成的域名服務對象類型。您必須指定[Include]屬性才能包含它們。但是,include屬性需要[Association]屬性。您無法指定[Association]屬性,因爲這是多對多關係,並且關聯屬性要求您指定外鍵。

解決方案是將對象包裝在數據傳輸對象(DTO)中。我不必對已在我的問題中的代碼進行重大更改。唯一改變的是在域服務類客戶的檢索:

public CustomerDTO GetCustomerById(int Id) 
{ 
    return new CustomerDTO(this.ObjectContext.Customers.Include("Contacts").SingleOrDefault(s => s.Id == Id)); 
} 

的解決方案的主要部分是改變DTO類添加到基礎實體框架模型:

[DataContract] 
public partial class CustomerDTO : Customer 
{ 

    public CustomerDTO() { } 
    public CustomerDTO(Customer customer) 
    { 
     if (customer != null) 
     { 
      Id = customer.Id; 
      Name = customer.Name; 
      CustomerContacts = new Collection<ContactDTO>(); 
      foreach (Contact d in customer.Contacts) 
      { 
       CustomerContacts.Add(new ContactDTO(d, Id)); 
      } 
     } 
    } 

    [DataMember] 
    [Include] 
    [Association("CustomerContacts", "CustomerId", "Id")] 
    public Collection<ContactDTO> CustomerContacts 
    { 
     get; 
     set; 
    } 
} 

[KnownType(typeof(CustomerDTO))] 
public partial class Customer 
{ 
} 

[DataContract()] 
public partial class ContactDTO : Contact 
{ 
    public ContactDTO() { } 
    public ContactDTO(Contact contact, int customerId) 
    { 
     if (contact != null) 
     { 
      Id = contact.Id; 
      FullName = contact.FullName; 
      CustomerId = customerId; 
     } 
    } 

    [DataMember] 
    public int CustomerId { get; set; } 
} 

[KnownType(typeof(ContactDTO))] 
public partial class Contact 
{ 
} 

需要KnownType,DataMemberDataContract屬性才能使其發揮作用。實際上,實例化對象需要在構造函數中更多地複製屬性。有沒有一種簡單的方法可以避免執行明確拷貝的代碼?我很樂意提供建議。

我曾希望避免引入額外的類,但由於所需的Association屬性需要外鍵規範,所以在多對多關係的情況下似乎不可避免。在我的情況下Contact.CustomerId

任何人都可以做得更好(==減少編碼)嗎?