【问题标题】:Select optional navigation property into new object将可选导航属性选择到新对象中
【发布时间】:2015-10-16 18:33:30
【问题描述】:

我有一组业务对象,我正在尝试使用实体框架查询填充这些对象。 MS-SQL 数据库和 EF 模型都反映了以下类。

请注意,ParentTypeChildType 通过“0..1 to Many”相关联。

问题是我想加载一个ParentType 对象作为ChildType 对象的属性,但是如所写,如果ParentType 为空,我会得到InvalidOperationException,因为@987654327 中的物化值@ 为空。

另外请注意,我不想将ParentType 数据展平为ChildType 中的可为空字段,因为稍后我想将结果列表按整个ParentType 对象分组。

Public Class ParentType
    Public Property ParentTypeID as Integer
    Public Property Description as String
End Class

Public Class ChildType
    Public Property ChildTypeID As Integer
    Public Property ParentTypeID As Integer?
    Public Property Description As String

    Public Property ParentType As ParentType

    Public Shared Function GetChildTypes() As IQueryable(Of ChildType)
        Dim db As New DataAccess.MyModelEntities()

        Return (
            From c In db.ChildTypes
            Select New ChildType With {
                .ChildTypeID = c.ChildTypeTypeID,
                .ParentTypeID = c.ParentTypeID,
                .Description = c.Description,
                .ParentType = New ParentType With {
                    .ParentTypeID = c.ParentType.ParentTypeID,
                    .Description = c.ParentType.Description
                }
            }
        )
    End Function
End Class

编辑:试图澄清,我正在寻找的是一种我可以按照书面形式执行New ParentType 的方法,但前提是 c.ParentType 不为空。

【问题讨论】:

  • 为什么ParentType 没有属性ChildTypes
  • 因为当我使用 ParentType 时,我从不需要 ChildType 集合;如果我这样做了,我会把它添加进去。
  • 好的,我想我只是想弄清楚你想要达到的目标。在实体类型中初始化上下文是不好的做法,而该实体类型本身是由另一个上下文初始化的。当你得到 ChildTypes 时,你不直接使用 db.ChildTypes.Include("ParentType") 吗?
  • @GertArnold 我不确定您所说的“在一个实体类型中初始化一个上下文,该实体类型本身由另一个上下文初始化”,因为唯一涉及的上下文是DataAccess.MyModelEntities“db”。其他类型(ParentTypeChildType)只是 POCO,根本没有 EF 关联。
  • 嗯,这从您的代码中远非显而易见。我只看到ChildTypedb.ChildTypes。我应该如何断定它们是不同的类型?以及如何“将ParentType 对象加载为ChildType 对象的属性”?听起来像 EF 加载。你的问题完全不清楚。无论如何,这段代码不属于业务类。

标签: vb.net entity-framework linq linq-to-entities


【解决方案1】:

哦,伙计 - 我自己过去也曾为此苦苦挣扎过。

在实体框架中,基本上它将导航属性保存为外键。这意味着当您加载具有导航属性的实体时,它不会同时加载属于该属性类型的实体的属性,因为它只有外键。

如果您想加载相关实体的属性,您必须使用 Eager Loading 将其包含在查询中(Gert Arnold 使用的示例),或者在此过程中查询其他表本身。

在你的特殊情况下,我猜你会使用这样的东西:

From c In db.ChildTypes
            Select New ChildType With {
                .ChildTypeID = c.ChildTypeTypeID,
                .ParentTypeID = c.ParentTypeID,
                .Description = c.Description,
                .ParentType = New ParentType With {
                    .ParentTypeID = c.ParentTypeID,
                    .Description = (From parent In db.ParentTypes Select parent.Description Where parent.ParentTypeID = c.ParentTypeID).FirstOrDefault()
                }

或者 Gert 推荐的 Eager Loading 方式:

Dim childTypesList = db.ChildTypes.Include("ParentTypes").ToListAsync()

【讨论】:

  • Hm... 上面代码的问题是 ParentTypeID 甚至整个 c.ParentType 对象有时为空。我当然不想为每个属性运行子查询,即使我这样做了,我仍然必须将值分配给可为空的属性,这是我想避免的事情之一。
【解决方案2】:

最后,我想我必须允许创建 ParentType 对象并允许其所有成员为空。对我来说,这不是理想的解决方案,但它使查询按书面方式工作。

Public Class ParentType
    Public Property ParentTypeID as Integer?
    Public Property Description as String
End Class

我可以检查ParentType.ParentTypeID.HasValue,而不是检查ParentType Is Nothing

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-20
    • 1970-01-01
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多