ADO.NET Entity Framework: проблема с обновлениями связанных объектов - PullRequest
0 голосов
/ 24 августа 2010

Я играю с небольшим приложением VB.NET с WPf / MVVM и ADO.NET EF на SQL Express-DB, и у меня возникают проблемы при попытке обновить связанные объекты:

В моей БД есть три таблицы «tb_Actors», «tb_Movies» и таблица соединений «tb_movies_actors».Дизайнер EF создает две сущности «Актеры» и «Фильмы» и правильно устанавливает их свойства навигации на основе внешних ключей.Так что смог создать представление, которое связывается со свойством viewModels, которое имеет все «Movies.Actors».

Сетка данных в моем представлении правильно отображает всех актеров, и - если это новый актер, которого нет в моей БД, - я могу добавить новых актеров в фильм и правильно сохранить изменения в БД.

Однако, если я хочу добавить актера в фильм, который уже находится в моей БД, я получу двойную запись в моей таблице tb_actors.Сначала я установил поля первичного ключа (name и id) в UNIQUE, но затем мой код ломается.Затем я добавил небольшую процедуру обновления, которая проверяет для каждого связанного актера фильма, является ли он известным актером, и заменяет идентификатор «новых актеров» на идентификатор «старых актеров» - это также прерывается.

Есть ли способ сообщить EF, что он должен определить, находится ли добавленный связанный объект (= уже известный актер, добавленный в фильм), уже в БД, и поэтому он должен вставлять только новую запись в соединительную таблицу, но нек таблице связанных объектов?

Моим следующим шагом будет отсоединение связанных объектов и выполнение всех обновлений / вставок в моем собственном коде доступа к данным… но, поскольку я считаю, что моя проблема связана с типичным сценарием использования EF, необходимобыть более элегантным способом обработки обновлений связанных объектов.

Любые мысли, ответы и советы приветствуются!

* РЕДАКТИРОВАТЬ Вот соответствующие фрагменты кода *

1) У меня есть следующая функция LoadMovies в моем классе доступа к данным MovieRepository:

Private Function LoadMovies() As List(Of Movies)
        movs = From m In dc.Movies.Include("Actors") Select m
        Return movs.ToList
End Function

2) Следующее свойство моего viewModel представляет актеров, связанных с определенным фильмом:

        Public ReadOnly Property actors() As ICollectionView
        Get
            If evs Is Nothing Then
                evs = New CollectionViewSource
                evs.Source = _movie.Actors
            End If
            Return evs.View
        End Get
        End Property

3) В моем представлении MovieDetail у меня есть привязка сетки данных к свойству:

<DataGrid Name="ActTestGrid" HorizontalAlignment="Left" VerticalAlignment="Stretch" ItemsSource="{Binding actors}" AutoGenerateColumns="False" Width="150" Height="120" Style="{StaticResource dgTemplate}" RowStyle="{StaticResource dgRowTemplate}" CellStyle="{StaticResource dgCellTemplate}" CanUserSortColumns="True" CanUserAddRows="True" CanUserDeleteRows="True" HeadersVisibility="None">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Path=name, UpdateSourceTrigger=PropertyChanged}" CanUserSort="true"/>
                </DataGrid.Columns>
</DataGrid>

4) Это мойФункция updateMovie моего MovieRepository (как сейчас):

Public Sub UpdateMovie(ByVal movie As Movies)
        If movie Is Nothing Then
            Throw New ArgumentNullException("Movie")
        Else

            dc.SaveChanges()
        End If
End Sub

1 Ответ

0 голосов
/ 16 августа 2011

EF делает то, что делает, и вы больше не можете сказать ему, что он не будет проверять ваши данные.EF вставит то, что вы говорите, чтобы вставить (или попытаться).Ответственность за проверку данных лежит перед вызовом сохранения изменений.

Чтобы обойти эту проблему, подумайте о предоставлении комбинированного списка в виде со списком имен актеров.Для поля со списком IsEditable установлено значение true, а текстовое свойство привязано к ActorName AS String в вашей модели представления.Если пользователь выбирает существующего актера, EF не будет пытаться вставить нового.Если пользователь вводит новое имя, EF создаст нового актера.

Вот некоторый код с использованием фирменного наименования:

Public Property BrandName() As String
    Get
        Return _brandName
    End Get
    Set
        _brandName = value.Trim()

        If _brandName <> String.Empty Then
            Dim b As Brand = _brands.ToList().Find(Function(br) br.BrandName.ToUpper() = _brandName.ToUpper())

            If b Is Nothing Then
                Brand = New Brand()
                Brand.BrandName = _brandName
            Else
                Brand = b
            End If
        Else
            Brand = Nothing
        End If

        CheckIsDirty()
        RaisePropertyChanged("BrandName")
    End Set
End Property

И в представлении:

<ComboBox Grid.Row="1" Grid.Column="0" Height="28" HorizontalAlignment="Stretch" Margin="110,0,28,0" VerticalAlignment="Top" TabIndex="1" ItemsSource="{Binding Brands}" DisplayMemberPath="BrandName" Text="{Binding BrandName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEditable="True"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...