Vb.net 实体框架codefirst中通过子实体的递归迭代

Vb.net 实体框架codefirst中通过子实体的递归迭代,vb.net,ef-code-first,Vb.net,Ef Code First,我已经使用EF Codefirst创建了一个VB.net WinForms程序和一个数据库。在其中一个表“Categories”中,有一个名为“ParentCategory_CategoryId”的列,它是该特定类别的父类别(注意,它可以为NULL)。这允许我对子类别进行无限量的嵌套。迄今为止,情况良好(类别定义如下): 当我试图用这些数据填充TreeView控件时,问题就出现了。我的意图是递归地遍历这些类别,为每个类别添加一个树节点,并为每个子类别添加一个子节点。VB代码如下所示: Priva

我已经使用EF Codefirst创建了一个VB.net WinForms程序和一个数据库。在其中一个表“Categories”中,有一个名为“ParentCategory_CategoryId”的列,它是该特定类别的父类别(注意,它可以为NULL)。这允许我对子类别进行无限量的嵌套。迄今为止,情况良好(类别定义如下):

当我试图用这些数据填充TreeView控件时,问题就出现了。我的意图是递归地遍历这些类别,为每个类别添加一个树节点,并为每个子类别添加一个子节点。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."

任何想法都将不胜感激。

查询中的Where子句包含一个Linq无法解析为实体的表达式:

dc.Categories.Where(Function(x) x.ParentCategory Is ParentCategory)
可以通过比较两个对象的关键点而不是它们的类型来避免这种情况:

dc.Categories.Where(Function(x) x.ParentCategory.CategoryId = ParentCategory.CategoryId)
或者,可以使用Linq to对象运行此查询。为此,在计算where子句之前,需要将类别数据作为对象集合检索:

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

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

实体框架不知道如何将类转换为实际的SQL。如果改为在where子句中使用CategoryId,它应该可以工作。我使用C#,因此希望以下内容有意义:

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

谢谢大家,这已经解决了问题,但我不得不将这两种情况分开:1)没有父类,2)有父类(解决方案如下)

我也搬家了

Dim dc as new myContext
在递归函数中,我生成了一个额外的错误(显然,在关闭数据上下文之前,不能重复使用它)


我知道我可以只将ParentCategoryId传递到递归函数中,而不是传递给Category对象本身。

虽然这可以确定问题所在,但我认为这不是一个好的解决方案。比较x.ParentCategory.CategoryId和ParentCategory.Id会更好,以便在SQL中保持比较。同意,这样做更有效。在比较中需要使用
=
而不是
Is
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