Entity framework 使用EF POCO对象获取只读数据绑定

Entity framework 使用EF POCO对象获取只读数据绑定,entity-framework,data-binding,entity-framework-4,binding,Entity Framework,Data Binding,Entity Framework 4,Binding,我正在使用EF4和WPF。我正在以主细节样式将数据绑定到DataGrid。想想Northwind客户->订单->订单详情 我发现,当我使用POCO对象时,Orders和OrderDetails网格是只读的。如果恢复使用设计器生成的实体,它们将变得可编辑 绑定XAML如下所示: <Window.Resources> <CollectionViewSource x:Key="CustomersViewSource" d:DesignSource="{d:DesignInst

我正在使用EF4和WPF。我正在以主细节样式将数据绑定到DataGrid。想想Northwind客户->订单->订单详情

我发现,当我使用POCO对象时,Orders和OrderDetails网格是只读的。如果恢复使用设计器生成的实体,它们将变得可编辑

绑定XAML如下所示:

<Window.Resources>
    <CollectionViewSource x:Key="CustomersViewSource" d:DesignSource="{d:DesignInstance my:Customer, CreateList=True}" />
    <CollectionViewSource x:Key="CustomersOrdersViewSource" Source="{Binding Path=Orders, Source={StaticResource CustomersViewSource}}" />
</Window.Resources>
<Grid DataContext="{StaticResource CustomersViewSource}">

    <DataGrid ItemsSource="{Binding}" >
    <DataGrid ItemsSource="{Binding Source={StaticResource CustomersOrdersViewSource}}" >
网格填充,但如果我使用POCO对象,则第二个是只读的,如果它们是标准EF生成的对象,则可编辑

关键似乎在实体的导航属性中。我的POCO对象使用:

Public Overridable Property Orders() As ICollection(Of Order)
    Get
        If _Orders Is Nothing Then  _Orders = New HashSet(Of Order)
   Return _Orders
    End Get
    Set(ByVal value As ICollection(Of Order))
        _Orders = value
    End Set
End Property
而EF对象要复杂得多:

<XmlIgnoreAttribute()>
<SoapIgnoreAttribute()>
<DataMemberAttribute()>
<EdmRelationshipNavigationPropertyAttribute("NorthwindModel", "FK_Order_Details_Orders", "Orders")>
Public Property Order() As Order
    Get
        Return CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value
    End Get
    Set
        CType(Me, IEntityWithRelationships).RelationshipManager.GetRelatedReference(Of Order)("NorthwindModel.FK_Order_Details_Orders", "Orders").Value = value
    End Set
End Property

公共财产秩序()作为秩序
得到
返回CType(Me,IEntityWithRelationships).RelationshipManager.GetRelatedReference(订单)(“NorthwindModel.FK\u Order\u Details\u Orders”,“Orders”).Value
结束
设置
CType(Me,IEntityWithRelationships).RelationshipManager.GetRelatedReference(订单)(“NorthwindModel.FK\u Order\u Details\u Orders”,“Orders”)。Value=Value
端集
端属性
由于缺少更好的措辞,EntityCollection类型的属性似乎有一些魔力。ICollection不是只读接口,哈希集也不是只读的

关于如何让POCO在这里工作,或者我被EF派生的对象卡住了,有什么想法吗?(使单元测试变得困难。)


谢谢。

在POCO示例中,问题可能是
订单
订单详细信息
集合的类型为
ICollection
/
哈希集
。WPF datagrid在内部不直接与集合一起工作,而是与关联的“集合视图”一起工作。将集合绑定到DataGrid时,WPF绑定引擎将根据集合的类型创建此内部集合视图

如果您的集合仅实现
IEnumerable
或仅实现
ICollection
,则创建的集合视图的类型为
CollectionView
,该类不实现IEditableCollectionView。这就是为什么在绑定哈希集时无法编辑DataGrid的原因

DataGrid需要一个集合视图,该视图实现
IEditableCollectionView
以允许编辑。例如,
ListCollectionView
(它也源自
CollectionView
)。如果源集合实现了
IList
接口,则WPF将创建这种类型的集合视图

因此,要解决此问题,您应该将POCO的
Orders
属性的类型更改为
IList

Public Overridable Property Orders() As IList(Of Order)
    Get
        If _Orders Is Nothing Then  _Orders = New List(Of Order)
        Return _Orders
    End Get
    Set(ByVal value As IList(Of Order))
        _Orders = value
    End Set
End Property
编辑


根据@Allon Guralnek下面的评论,有必要实现非通用的IList接口,以获得可编辑的数据网格。这是
列表(Of T)
的情况,因此上面的代码仍然有效。其他只实现了通用的
IList(Of T)
而没有实现非通用的
IList
的实现不会使DataGrid可编辑。

ICollection的具体实例可以是只读的。这取决于实例化集合时使用的类型。例如,
ReadOnlyCollection
是一个只读的ICollection。由于POCO
Orders
属性的setter是公共的,因此根据您为属性指定的集合,您可以拥有只读的Orders集合。如何填写客户对象的订单集合?通过延迟加载?@Slauma:目前是延迟加载。然而,我的第一个POCO模板具有只读导航属性。属性必须使用内部创建的HashSet,该HashSet应该是可编辑的。允许外部对象用新集合引用替换类内部管理的集合引用对我来说没有意义。因此,原始POCO类具有只读导航属性。哈希集是可编辑的,但无法更改对它的引用。为了解决这个问题,我将导航属性改为读写。这就解决了这个问题。我已经将T4模板改为使用IList,现在一切都很好。详细解释的加分(如果我能给加分的话!)。老实说,我对EF和WPF有点不安,因为它们隐藏了太多的复杂性,很难找到问题的根本原因。谢谢大家!@用户458314:您需要额外获得7点声誉积分(至少15点)才能“给予奖励积分”(也称为“投票支持”);)我同意,通常很难发现问题的根源,特别是在WPF中。我只能回答你的问题,因为我突然想起大约一个月前我也有同样的问题。当我双击DataGrid时出现了一个异常,异常告诉我关于“EditItem不可能与此视图一起使用”或类似内容。这是一个开始搜索的小提示。尽管如此,我还是花了一些时间才找到最终原因。我只是想澄清一下,为了使
数据网格
可编辑,必须将其绑定到实现非泛型
IList
接口的集合(如果只实现泛型
IList
/
IList(Of T)
,那么它将不可编辑)。
List
/
List(Of T)
类恰好实现了这两个功能。我将HashSet更改为List,它解决了这个问题-但是如果我更新TT文件,我将再次面临这个问题。有没有一种方法可以让EF 6.1始终成为他们的列表?@Dani:我相信,修改T4模板是唯一的方法。
Public Overridable Property Orders() As IList(Of Order)
    Get
        If _Orders Is Nothing Then  _Orders = New List(Of Order)
        Return _Orders
    End Get
    Set(ByVal value As IList(Of Order))
        _Orders = value
    End Set
End Property