如何在 EF 中的 DbContext 上使用 Find 或 Find<T>?

Posted

技术标签:

【中文标题】如何在 EF 中的 DbContext 上使用 Find 或 Find<T>?【英文标题】:How to use Find or Find<T> on DbContext in EF? 【发布时间】:2021-11-04 23:14:41 【问题描述】:

NB我不是在问如何在数据库中查找/过滤实体。我不是在问FindWhere 之间的区别。我不是在问泛型的含义。

根据the docs,DbContext 提供了方法FindFind&lt;T&gt;。通常,我通过DbSet,但注意到在上下文和数据库集上都有Add(),我想看看如果我也尝试直接在上下文而不是数据库集上过滤会发生什么。

不过,我还没有找到一个这样的调用示例。很多关于通过数据库集的信息以及顶部免责声明中提到的差异。但我没有看到直接在上下文中显示 Find()Find&lt;T&gt;() 用法的示例。

有可能吗?如果有,怎么做? Intellisense 很神秘……

【问题讨论】:

当你想通过主键查找时使用Find。注意到主键可能很复杂。例如,您有表Person,其中ID (int) 是主键,那么您可以将整数值传递给Find。你有另一个表PersonAddress,主键是(PersonID, AddressID)。然后你需要传递一个匿名对象,例如Find(new 1, 2). @LeVu 我考虑过这种可能性,但对我来说没有意义,因为它通常不连贯。就个人而言,我是 GUID 的忠实信徒,所以我被覆盖了,但是有很多人更喜欢整数作为 ID,然后你最终会遇到一堆具有相同 ID 的不同实体/实例。会有 ID 等于 1234 的客户,还有订单、发票等。为什么在这种情况下他们还要发布方法?似乎我错过了一些东西(因为我深信 MS 的编码人员没有)。 【参考方案1】:

它做同样的事情,但不使用DbSet。它通过指定您要获取的type(实体)来工作。您只需指定类型,该类型必须与您的 DbSet 匹配。

有可能吗?如果有,怎么做?

public class MyContext : DbContext

    public MyContext(DbContextOptions<MyContext> options) : base(options)  

    public DbSet<City> Cities get; set; 
    public DbSet<State> States  get; set; 

然后像这样使用它:

MyContext context = CreateContext() // Or inject it...

// Will return the City which have id == 5. 
object myUntypedCity = context.Find(typeof(City), 5);

// Will return the city which have id == [your guid].
City myTypedCity = context.Find<City>(Guid.NewGuid());

作为旁注; Context 上的Add() 的工作方式相同。它将检测它是哪个type 实体并将其放在正确的DbSet 上。我不知道如果你有多个DbSet 使用相同的type 会发生什么。

为什么我们在上下文中有一个非泛型 Find() DB 使用整数作为 ID,因此确保了不明确的 ID 值 不同实体/表之间

在某些情况下,您可能不会公开DbSet,或者您只知道实体的type。这在制作一些非常通用的代码时非常方便,因为您没有类型化实体,也不知道它有什么类型的 id(主键)。它可能是Guidint。我本人从未在DbContext 上找到Find 的实际用途。

【讨论】:

@KonradViltersten 据我了解,您想知道如何使用它?不是它的作用?如果是这样,我也很乐意将其放入答案中。 这是您的答案,因此您可以添加任何您认为合适的内容。即使从技术上讲超出了原始问题的确切范围,我也欣赏内容的一定弹性。然而,我的评论是针对“法比奥”的一些评论,直到现在我才意识到它一定是被删除的评论。我没有收到任何通知,我的大脑发出了合乎逻辑的嘘声。 (现已删除)评论是关于什么的? 另外,如果您愿意,听听您对我们为什么在上下文中使用非通用Find() 的看法会很有趣,因为很多数据库都使用整数作为 ID,因此确保不同实体/表之间的 ID 值不明确(请参阅问题下方的 cmets)。 @KonradViltersten,你是对的。这是对已删除评论的回答。 Find 也可以在 DbSet 上使用。 太棒了!我冒昧地对其进行了一些编辑。将城市和州结合起来可能会让新开发人员感到有些困惑。此外,返回的类型很明显,因为您使用的是硬性和显式类型变量(如上帝所愿)。希望你不要介意。【参考方案2】:

当您在 DbSet 上使用 Find 时,实体的类型是已知的,因此只需通过提供的 ID 查找即可。

当您在 DbContext 上使用 Find 时,您要么必须告诉 EF 从其已知映射中找到哪个 Type(实体),要么您可以使用定义实体的 Type 的通用版本搜索。

为什么要使用这些方法而不是DbSet.Find?一个示例是您不想将域的某个方面公开为DbSet。例如,如果您有一个客户、企业等的 DbSet,它们都包含对地址实体的引用,那么很少需要在该范围之外加载地址,因此您可能会选择不在您的域可能会因方便而被滥用。如果您的 DbContext 确实需要定位特定地址,您可以使用 DbContext.Find&lt;Address&gt;(addressId) 来加载它。

老实说,我不使用DbContext.Find(),我什至不使用DbSet.Find(),我非常非常喜欢使用IQueryable 和投影。但是,嘿,这是一个选择。 :)

【讨论】:

我分享您使用数据库集的观点。这是的路要走。然而,最近,我注意到一些 Mongo-devs 使用Find 并且(在最初假设这是“他们”的方式之后)我发现“普通”数据库也有Find。仔细阅读它会发现它的性能更高,因为它只有在内存中没有实例副本的情况下才会访问数据库。所以我们可能做错了,你和我。然后,我开始四处寻找以验证/伪造我的经验教给我的东西。 从平均定律来看,我并不太担心。通过在 Linq 和 IQueryable 上进行标准化,我经常选择数据位,或者像 Any 那样检查是否存在。 Find 可能为我保存一个数据库命中,或者如果我对其进行标准化,它可能会导致拉整个实体。我希望我的数据层可以模拟,所以IQueryable 可以作为更好的默认 IMO。按 ID 查询是一种快速操作,如果有更严重的情况并且我认为大多数条目应该已经加载,我可以随时检查 DbSet.Local 此外,由于大多数 DbContext 实例的生命周期应该相对较短,并且在 DbContext 中拥有大量跟踪的实例可能会对不相关的操作产生负面的性能影响,从而导致使用像 AsNoTracking 这样的功能, Find 很可能最终会在大多数情况下访问 DB,或者如果与长寿命、高跟踪计数 DbContexts 结合使用,则可能导致整体缓慢。 (以及潜在的过时数据问题) 你提出了两个很好的观点。我同意他们的观点(因为它们与我习惯的方式相关)但是当我与有不同观点的同事讨论上述问题时,你现在给了我一个简洁的表述来传达和激励这一点。这是我的弱点——能够激励和影响我的同龄人。当我没有这样做时,最终我开始质疑我的建议。 (这通常会导致进展不佳......)所以你的评论对我来说非常有价值。

以上是关于如何在 EF 中的 DbContext 上使用 Find 或 Find<T>?的主要内容,如果未能解决你的问题,请参考以下文章

EF中的DbContext类

关于EF实体框架中的 dbContext

如何在 EF Core 中实例化 DbContext

如何使用 caliburn micro 在 Wpf 中注入 EF DbContext

如何将时态表添加到 EF Code-First DBContext?

如何在 DDD 中使用 EF DbContext 分离我的聚合