Получение данных только для чтения с использованием объектов EF POCO - PullRequest
2 голосов
/ 22 марта 2011

Я использую EF4 с WPF. Я привязываю данные к DataGrid в стиле Master-Detail. Подумайте о клиентах Northwind -> Заказы -> OrderDetails.

Я обнаружил, что при использовании объектов 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}}" >

(Конечно, я удалил атрибуты, не относящиеся к привязке данных).

Тогда есть стандартное событие загрузки формы для привязки экземпляра контекста:

Dim NorthwindEntities As BindTest.NorthwindEntities = New BindTest.NorthwindEntities()
Dim CustomersViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("CustomersViewSource"), System.Windows.Data.CollectionViewSource)
CustomersViewSource.Source = NorthwindEntities.Customers

Сетки заполняются, но вторая доступна только для чтения, если я использую мои объекты 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

Из-за отсутствия лучшей формулировки в атрибутах типа EntityCollection, похоже, есть какая-то магия. ICollection не является интерфейсом только для чтения, а HashSet также не доступен только для чтения.

Есть какие-нибудь идеи о том, как заставить POCO работать здесь, или я застрял с объектами EF? (Затрудняет юнит-тестирование.)

Спасибо.

1 Ответ

4 голосов
/ 22 марта 2011

Возможно, проблема в том, что коллекции Orders и OrderDetails имеют тип ICollection<T> / HashSet<T> в вашем примере POCO.Сетка данных WPF внутренне не работает с коллекцией напрямую, а скорее со связанным «представлением коллекции».Когда вы связываете коллекцию с DataGrid, механизм связывания WPF создает это внутреннее представление коллекции на основе типа коллекции.

Если ваша коллекция реализует только IEnumerable или только ICollection тип созданной коллекцииview - это CollectionView, класс, который не реализует IEditableCollectionView.Вот почему вы не можете редактировать DataGrid, когда привязываете к нему HashSet.

DataGrid требуется представление коллекции, которое реализует IEditableCollectionView, чтобы разрешить редактирование.Это, например, ListCollectionView (который также происходит от CollectionView).WPF создает этот тип представления коллекции, если ваша исходная коллекция реализует интерфейс IList.

Итак, чтобы решить эту проблему, вы должны изменить тип свойства Orders вашего POCO на 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, чтобы получитьредактируемый DataGrid.Это относится к List(Of T), поэтому приведенный выше код будет работать.Другие реализации, которые реализуют только универсальный IList(Of T), но не универсальный IList, не сделают DataGrid редактируемым.

...