【问题标题】:Restrict EF query to a base type with TPT inheritance将 EF 查询限制为具有 TPT 继承的基本类型
【发布时间】:2012-08-29 22:14:03
【问题描述】:

考虑以下具有 TPT 继承的实体框架模型。

数据库表:

Person (PersonID, Name)
Student (PersonID, Grade)

EF 实体:

Person (PersonID, Name)
Student (Grade) : inherits from Person

现在,当您尝试从数据库中选择人员条目时,它将返回 Student 类型。

var person = db.Persons.First();
// person here is of type Student and has Grade peoperty populated
// SQL query generated by EF selects data from both tables with a JOIN

如何强制此查询仅从 Person db 表中选择数据,而不是从 Person 和 Student db 表中选择?

例如,可以使用以下查询来完成:

db.Persons.Select(x => new Person { PersonID = x.PersonID, Name = x.Name }).First() 

但它看起来很蹩脚,在现有查询上生成额外的 SELECT 语句,这样返回的 Person 实体对象将不会被 EF 上下文跟踪。所以,我想知道为什么db.Persons.First() 返回一个Student 对象?这不是违反直觉吗?

【问题讨论】:

    标签: c# .net linq entity-framework linq-to-entities


    【解决方案1】:

    如果您使用Person 的列表并将单个Student 存储到列表中,当您调用First 时会收到什么?您将收到一个 Student 实例,因为这就是面向对象代码的工作方式 Student 是一个 Person 但如果不创建新实例并从原始 Student 复制数据,您将永远不会只获得 Person 实例实例。

    EF 以同样的方式工作——实体是原子的。它跨越多少个表并不重要。如果您查询继承层次结构,您将始终获得正确类型的整个实例,因为这就是面向对象代码的工作方式。

    如果在 Linq-to-entities 中使用,您的第二个示例根本不应该工作,因为您正在查询中创建实体的实例 - 这是不允许的。不得对映射实体进行投影,因为这可能会破坏数据一致性。

    要走的路是使用投影到非实体类型 - 自定义未映射类或匿名类型。

    【讨论】:

    • 感谢您的澄清!非常感谢。
    • 假设我有一个Document 基类并且我的其他一些类继承了它,有一些复杂的关系,如果我只想获取基类字段怎么办(用于显示Document 的基本属性,即DocumentOwnerDocumentCreationDate,...)? EF 生成一个非常复杂的 sql,这会降低性能。
    • @Masoud:你必须使用投影。
    【解决方案2】:

    试试这段代码

    db.Persons.TypeOf<Person>().First();
    

    【讨论】:

    • 不,这样它只是在两个现有的 SELECT 周围再添加一个 SELECT 包装器,并且仍然从两个数据库表中获取数据。 person 变量的类型为 Student
    • 悲伤我添加了新语法
    • 这种语法也不能解决问题。 db.Persons.First()db.Persons.OfType&lt;Person&gt;().First() 产生相同的查询和返回值。
    • 悲伤你的问题我很抱歉,但你的问题是:如何强制此查询仅从 Person db 表中选择数据,而不是从 Person 和 Student db 表中选择数据?
    • 我不明白这个问题,请
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-18
    • 1970-01-01
    • 1970-01-01
    • 2021-07-27
    • 1970-01-01
    • 1970-01-01
    • 2011-06-20
    相关资源
    最近更新 更多