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