首先通过实体框架代码中的Child实体进行递归迭代

时间:2013-06-25 15:38:17

标签: vb.net ef-code-first

我使用EF Codefirst创建了一个VB.net WinForms程序和一个数据库。在其中一个表“Categories”中,有一个名为“ParentCategory_CategoryId”的列,它是该特定类别的父类别(nb可以为NULL)。这允许我为子类别设置无限量的嵌套。到目前为止,这么好(下面的类别定义):

Public Class Category
    Public Property CategoryId As Integer
    Public Property CategoryName As String

    Public Overridable Property ChildCategories As List(Of Category)
    Public Overridable Property ParentCategory As Category
End Class

当我尝试使用此数据填充TreeView控件时出现问题。我的目的是递归遍历类别,并为每个类别添加一个TreeNode,并为每个子类别添加一个子节点。 VB代码如下:

Private Sub Categories_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' Create new data context        
    Dim dc As New MyContext
    ' Call the recursive function once with Parent category as nothing
    LoadNodesOntoTreeview(dc, Nothing, Nothing)

End Sub

Public Sub LoadNodesOntoTreeview(dc As MyContext, Optional ParentCategory As Category = Nothing, Optional ByRef ParentNode As TreeNode = Nothing)
    Try
        For Each c As Category In dc.Categories.Where(Function(x) x.ParentCategory Is ParentCategory).ToList
            Dim n As New TreeNode With {.Text = c.CategoryName}
            LoadNodesOntoTreeview(dc, c, n)
            If ParentNode Is Nothing Then
                TreeView1.Nodes.Add(n)
            Else
                ParentNode.Nodes.Add(n)
            End If
        Next
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Sub

对于第一次迭代(ParentCategory = Nothing),这可以正常工作,但调用时会出现问题

LoadNodesOntoTreeview(dc, c, n)

在iteslf内。我收到错误:

"Unable to create a constant value of
type 'System.Data.Entity.DynamicProxies.Category_D3161C0FA58DECDDCD3237
36A77B49BF9AC13F6AB1D9C56D7946173054210834'. Only primitive types or
enumeration types are supported in this context."

非常感谢任何想法。

3 个答案:

答案 0 :(得分:1)

查询中的Where子句包含Linq to Entities无法解析的表达式:

dc.Categories.Where(Function(x) x.ParentCategory Is ParentCategory)

您可以通过比较两个对象的键而不是它们的类型来避免这种情况:

dc.Categories.Where(Function(x) x.ParentCategory.CategoryId = ParentCategory.CategoryId)

或者,您可以使用Linq to Objects运行此查询。为此,您需要在评估where子句之前将Categories数据检索为对象集合:

dc.Categories.ToList().Where(Function(x) x.ParentCategory Is ParentCategory)

显然,这可能意味着通过线路传递更多数据,因此第一种方法更可取。

答案 1 :(得分:1)

实体框架不知道如何将类转移到实际的SQL。如果您在where子句中使用CategoryId,它应该可以工作。我使用C#,所以希望以下是有道理的:

For Each c As Category In dc.Categories.Where(Function(x) x.ParentCategory.CategoryId = ParentCategory.CategoryId).ToList

答案 2 :(得分:0)

谢谢大家,已经解决了这个问题,但我不得不分开两个案例,其中类别有1)没有父母和2)父母(下面的解决方案)。

我也搬家了

Dim dc as new myContext

在递归函数中,因为我生成了一个额外的错误(数据上下文在关闭之前无法重复使用 - 显然!)。

Private Sub Categories_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    LoadNodesOntoTreeview()
End Sub

Public Sub LoadNodesOntoTreeview(Optional ParentCategory As Category = Nothing, Optional ByRef ParentNode As TreeNode = Nothing)
    Try
        Dim dc As New MyContext
        If ParentCategory Is Nothing Then
            For Each c As Category In dc.Categories.Where(Function(x) x.ParentCategory Is Nothing)
                Dim n As New TreeNode With {.Text = c.CategoryName}
                LoadNodesOntoTreeview(c, n)
                TreeView1.Nodes.Add(n)
            Next
        Else
            For Each c As Category In dc.Categories.Where(Function(x) x.ParentCategory.CategoryId = ParentCategory.CategoryId).ToList
                Dim n As New TreeNode With {.Text = c.CategoryName}
                LoadNodesOntoTreeview(c, n)
                ParentNode.Nodes.Add(n)
            Next
        End If
    Catch ex As Exception
        MsgBox(ex.Message)
    End Try
End Sub

我知道我只能将ParentCategoryId传递给递归函数而不是Category对象本身。