如何使用实体框架和ASP.NET Web API(Visual Basic)将域对象的子集合转换为自定义对象的集合?

如何使用实体框架和ASP.NET Web API(Visual Basic)将域对象的子集合转换为自定义对象的集合?,asp.net,entity-framework,linq,Asp.net,Entity Framework,Linq,我的模型中有以下由数据库自动生成的域类: Public Class Person Public Property id As Integer Public Property lastName As String Public Property addresses As ICollection(Of Address) = New HashSet(Of Address)() End Class Public Class Address Public Property

我的模型中有以下由数据库自动生成的域类:

Public Class Person
    Public Property id As Integer
    Public Property lastName As String
    Public Property addresses As ICollection(Of Address) = New HashSet(Of Address)()
End Class

Public Class Address
    Public Property id As Integer
    Public Property personId As Integer
    Public Property addressLine As String
End Class
我创建了以下自定义DTO类来表示传递给用户的数据:

Public Class PersonDTO
    Public Property lastName As String
    Public Property addresses As ICollection(Of AddressDTO) = New HashSet(Of AddressDTO)()
End Class

Public Class AddressDTO
    Public Property addressLine As String
End Class
我想执行以下操作来查询数据库并返回PersonDTO对象的集合,每个对象都有AddressDTO对象的集合:

Using db as New DatabaseContext()

    Dim people As IQueryable(Of PersonDTO) =
        db.Persons.Include("addresses")
        .Select(Function(p) New PersonDTO With
        {
            .lastName = p.lastName,
            .addresses = p.addresses.Select(Function(a) New AddressDTO With {.addressLine = a.addressLine}).ToList()
        })

End Using
出于某种原因,此查询会编译,执行时不会抛出任何异常,但不会返回任何数据,事实上,我的客户机在运行时会收到一个Server500错误。但是,如果我将代码更改为以下内容(这将公开域对象,我不希望这样做),它就可以正常工作:


提前感谢您的帮助

经过大量挖掘,我在这里找到了答案:

我必须将DTO的嵌套集合作为匿名类的属性进行投影。通过这种方式,它可以将其保持为一个IQueryable,而不是将其实现为一个列表。然后,我可以调用ToListSync一次性查询数据库,然后使用LinqTo对象将AddressDTO集合放入PersonDTO。以下代码适用于我:

Using db as New DatabaseContext()

    Dim anonymousPersonDTOList =
         db.Persons.Include("addresses")
         .Select(Function(p) New With
            {
                .pDTO = New PersonDTO With
                    {
                        .lastName = p.lastName
                    },
                .addresses = p.addresses.Select(Function(a) New AddressDTO With
                    {
                        .addressLine = a.addressLine
                    })
            }).ToListAsync()

    Dim personDTOList as IEnumerable(Of PersonDTO) =
        anonymousPersonDTOList.Select(
            Function(p)
                p.pDTO.addresses = p.addresses.ToList()
                Return p.pDTO
            End Function)

    Return personDTOList

End Using

当您以.ToList()结束语句时会有什么不同吗?如果您告诉我们错误,这会有所帮助调试时没有错误,它会很好地逐步完成查询。问题是它不返回任何数据,Web API生成500 HTTP响应代码。调试过程中我注意到的一件事是,当单步执行代码时,IQueryable对象一旦碰到内部select地址DTO,就会“消失”。我的意思是,在此之前,我可以在调试器中读取对象的属性,但一旦它点击内部选择,调试器就会突然说它没有声明,或者我没有权限查看它的属性。非常奇怪…Ruard van Elbirg-我还没有尝试对整个查询执行ToList…我会在有机会的时候尝试,并让您知道它是如何进行的。尽量不要使用块在
中返回
IQueryable
,只需使用
返回
DTO
类的列表即可
转换到DTO类后…因为我认为在查询实际返回结果之前这是一个上下文处理问题。。。
Using db as New DatabaseContext()

    Dim anonymousPersonDTOList =
         db.Persons.Include("addresses")
         .Select(Function(p) New With
            {
                .pDTO = New PersonDTO With
                    {
                        .lastName = p.lastName
                    },
                .addresses = p.addresses.Select(Function(a) New AddressDTO With
                    {
                        .addressLine = a.addressLine
                    })
            }).ToListAsync()

    Dim personDTOList as IEnumerable(Of PersonDTO) =
        anonymousPersonDTOList.Select(
            Function(p)
                p.pDTO.addresses = p.addresses.ToList()
                Return p.pDTO
            End Function)

    Return personDTOList

End Using