Мне нужна помощь в понимании ADO.NET Entity Framework.
Я пытаюсь представить иерархические данные и управлять ими в элементе управления WPF TreeView с помощью ADO.NET Entity Framework.
Объект ADO.NET Entity Framework с родителями и дочерними элементами http://img14.imageshack.us/img14/7158/thingpi1.gif
Каждая из этих вещей имеет одного родителя и ноль или более детей.
Моя кнопка "Удалить" ...
Private Sub ButtonDeleteThing_Click(...)
db.DeleteObject(DirectCast(TreeViewThings.SelectedItem, Thing))
db.SaveChanges()
End Sub
Я наблюдаю за профилировщиком SQL Server во время отладки приложения:
- Первое нажатие кнопки удаляет просто отлично.
- Вторым нажатием кнопки вставляется дублирующийся родительский элемент (но с пустым первичным ключом уникального идентификатора GUID), а затем выполняется удаление.
- Сбой третьего нажатия кнопки (нарушение ограничения PRIMARY KEY), поскольку он не может вставить другую строку с пустым первичным ключом GUID.
Неожиданное, сгенерированное дублирование T-SQL ...
exec sp_executesql N'insert [dbo].[Thing]([Id], [ParentId], ...)
values (@0, @1, ...) ',N'@0 uniqueidentifier,@1 uniqueidentifier,...',
@0='00000000-0000-0000-0000-000000000000',
@1='389D987D-79B1-4A9D-970F-CE15F5E3E18A',
...
Но это не просто удаление. Моя кнопка «Добавить» имеет похожее поведение с неожиданными вставками. Это следует той же схеме.
Это заставляет меня думать, что есть более фундаментальная проблема с тем, как я связываю эти классы сущностей с WPF TreeView или с самой моей моделью данных.
Вот соответствующий код ...
XAML ...
<TreeView Name="TreeViewThings"
ItemsSource="{Binding}"
TreeViewItem.Expanded="TreeViewThings_Expanded"
TreeViewItem.Selected="TreeViewThings_Selected"
... >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Thing}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Path=Title}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
<Button Name="ButtonAddThing" Content="Add Thing" ... />
<Button Name="ButtonDeleteThing" Content="Delete Thing" ... />
Visual Basic ...
Partial Public Class Window1
Dim db As New ThingProjectEntities
Private Sub Window1_Loaded(...) Handles MyBase.Loaded
TreeViewThings.ItemsSource = _
From t In db.Thing.Include("Children") _
Where (t.Parent Is Nothing) _
Select t
End Sub
Private Sub TreeViewThings_Expanded(...)
Dim ExpandedTreeViewItem As TreeViewItem = _
DirectCast(e.OriginalSource, TreeViewItem)
LoadTreeViewChildren(ExpandedTreeViewItem)
End Sub
Sub LoadTreeViewChildren(ByRef Parent As TreeViewItem)
Dim ParentId As Guid = DirectCast(Parent.DataContext, Thing).Id
Dim ChildThings As System.Linq.IQueryable(Of Thing)
ChildThings = From t In db.Thing.Include("Children") _
Where t.Parent.Id = ParentId _
Select t
Parent.ItemsSource = ChildThings
End Sub
Private Sub ButtonAddThing_Click(...)
Dim NewThing As New Thing
NewThing.Id = Guid.NewGuid()
Dim ParentId As Guid = _
DirectCast(TreeViewThings.SelectedItem, Thing).Id
NewThing.Parent = (From t In db.Thing _
Where t.Id = ParentId _
Select t).First
...
db.AddToThing(NewThing)
db.SaveChanges()
TreeViewThings.UpdateLayout()
End Sub
Private Sub ButtonDeleteThing_Click(...)
db.DeleteObject(DirectCast(TreeViewThings.SelectedItem, Thing))
db.SaveChanges()
End Sub
...
End Class
Что я делаю не так? Почему он генерирует эти странные вставки?
Обновление:
Я сделал прорыв. Но я до сих пор не могу это объяснить.
Я избавился от причины, когда упростил код для этого вопроса.
Вместо использования Linq, например:
From t In db.Thing.Include("Children") Where ...
Я использую Linq, например:
From t In db.Thing.Include("Children").Include("Brand") Where ...
Видите ли, сущность My Thing связана с другой сущностью Бренда.
ADO.NET Entity Framework Object с родителем и потомками и связанным объектом http://img25.imageshack.us/img25/3268/thingbrandct4.gif
Я думал, что это не имеет значения, поэтому я не включил его в вопрос выше.
Очевидно, это было причиной моих неожиданных проблем с вставками в мою таблицу Thing.
Но почему? Кто-нибудь может объяснить, почему это происходит? Я хотел бы понять это лучше.