我有一个实体框架,客户和联系人之间存在多对多的关系。
我已经生成了一个域服务类,并手动添加了以下方法。
public Customer GetCustomerById(int Id)
{
return this.ObjectContext.Customer.Include("Contacts").SingleOrDefault(s => s.Id == Id);
}
我现在想要创建一个页面,向我显示客户详细信息以及与该客户关联的联系人列表。
我在customerdetails.xaml的codebehind中有以下内容来读取传递到页面的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>
当我这样做时,文本框通过数据绑定很好地填充,但列表框仍然是空的。
两个问题:
我可以以某种方式指定回报 GetCustomerById查询的类型, 所以我可以看到我的名字 通过指定绑定 属性GUI?
我在做什么 错了吗?为什么不是我的ListBox 填充?我是以正确的方式进行此操作还是需要在代码隐藏中设置列表框的数据绑定?如果是这样,怎么样?我还没有找到如何通过编程方式通过域数据源访问Contacts属性。
我使用silverlight和实体框架4。
答案 0 :(得分: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
,DataMember
和DataContract
属性才能使其生效。实际上,实例化对象将需要在构造函数中进行更多的属性复制。是否有一种简单的方法可以避免代码执行显式复制?我愿意接受建议。
我希望避免引入额外的类,但是在多对多关系的情况下似乎是不可避免的,因为需要外键规范的必需Association
属性;就我而言Contact.CustomerId
。
任何人都可以做得更好(==少编码)吗?