【问题标题】:query using Foreign Key property or navigation property? EF 4.1使用外键属性或导航属性查询?英孚 4.1
【发布时间】:2011-09-27 10:37:37
【问题描述】:

我正在将一些 POCO 类映射到具有多个查找表的现有数据库,我想知道最有效或最推荐的方法是什么。

假设有一个映射到 Employee 表的 Employee 模型类:

public class Employee
{
    public int ID { get; set }
    public string Name { get; set }

    [ForeignKey("Role")]
    public int RoleID { get; set }
    public virtual EmployeeRole Role { get; set }
}

EmployeeRole 类/表看起来像:

public class EmployeeRole
{
    public int ID { get; set } // For instance: 1
    public string Description { get; set } // for instance: Manager
}

我知道我不需要显式声明外键 RoleID,但实际上我必须执行相当多的查询,这些查询依赖于具有“Manager”EmployeeRoleEmployee

现在的问题是,在结合效率、代码可读性和“数据独立性”方面,哪个更好? 假设 employees 是刚刚从存储库中提取的 IQueryable

  1. employees.Where(e => e.RoleID == 1);
  2. employees.Where(e => e.EmployeeRole.ID == 1);
  3. employees.Where(e => e.EmployeeRole.Description == "Manager");

2 和 3 的缺点是必须延迟加载导航属性,但 1 的缺点是 RoleID == 1 相当无意义并且绑定到数据库的当前状态。

我应该如何进行?有选项4吗?

【问题讨论】:

  • 对您的句子“2 和 3 的缺点是必须延迟加载导航属性”只有一个注释。我不认为EmployeeRole 导航。属性被延迟加载。您不会在查询中访问 Employee 对象的具体实例,但您只是在表述一个 Expression,稍后将其翻译成 SQL。不涉及延迟加载。拥有外键属性对于读取操作并不那么有趣(使用 nav.prop. 的 ID 也是如此,正如下面的答案所证明的那样),它对于更新/插入更重要。 1和2其实是一样的。
  • @Slauma - 你是对的,谢谢。我实际上意识到,当 J. Tihon 在他的答案上发布 Trace 结果时。再次感谢!

标签: c# query-optimization entity-framework-4.1


【解决方案1】:

我的猜测是,所有 3 个查询都会产生相似的结果。至少 1 和 2 应该产生相同的 SQL。您可以通过在 ObjectSet 实例上调用“ToTraceString”来查看生成的 SQL 语句(我必须查找它,可能隐藏在其他地方)。

-- 编辑 我重新创建了您的模型,发现使用了以下查询(SQL Server)。您必须将查询转换为提供 ToTraceString() 方法的 System.Data.Objects.ObjectQuery。

employees.Where(e => e.RoleID == 1);
employees.Where(e => e.EmployeeRole.ID == 1);

// Both result in:
SELECT [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[RoleId] AS [RoleId]
FROM [dbo].[Employees] AS [Extent1]
WHERE 1 = [Extent1].[RoleId]

employees.Where(e => e.EmployeeRole.Description == "Manager");

SELECT  [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[RoleId] AS [RoleId]
FROM  [dbo].[Employees] AS [Extent1]
INNER JOIN [dbo].[Roles] AS [Extent2] ON [Extent1].[RoleId] = [Extent2].[Id]
WHERE N'Manager' = [Extent2].[Name]

【讨论】:

  • Tihon - 很酷,谢谢并为此 +1。我不知道 EF 足够聪明,无法为选项 1 和 2 生成相同的查询。不过事后看来是有道理的。这种也排除了选项 3。不过,很遗憾RoleID == 1 是这样毫无意义的代码......对此有什么建议吗?
  • 我不太确定我是否理解您的问题。当然,您永远不知道“1”是否实际上是角色“经理”的 ID,但您始终可以在执行所有相关查询之前查询 Manager-ID。
  • 我只是想看看在这种情况下是否有一个完美的解决方案,一个在尽可能可读和可维护的同时尽可能少地影响数据库的解决方案。
【解决方案2】:

有点晚了,但我在表格中引入了“标志”的概念并取得了巨大成功。例如,如果您知道您可能经常查询经理的内容,请在名为 “经理”,在您的代码中只需执行e.EmployeeRole.Manager 即可。强类型并具有真正的商业意义。

【讨论】:

    猜你喜欢
    • 2014-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多