有没有办法将 DbContext 分解为 ASP.NET 6 框架中的区域?

发布于 2025-01-17 09:46:23 字数 1005 浏览 1 评论 0 原文

我正在ASP.NET 6 Framework的顶部创建Web应用程序。我试图找出用于此项目的最佳ORM。由于以下原因,我倾向于实体框架,

  1. 我将能够使用 linq 要编写我的查询,
  2. 我将能够使用本机C#模型轻松,直接访问我的关系。

这是并发症开始的地方。该应用程序将连接到具有超过500个表的非常大的数据库。此外,该应用程序将被分解成许多小逻辑区域因此,我很容易维护它。

如果实体框架是要走的路,我应该如何设置 dbContext 以便我可以管理500+ dbset 和关系?换句话说,即使我的应用程序被分解为多个领域,我是否应该为整个应用程序创建一个 dbContext ?还是我应该为每个区域创建 dbContext ?但是,如果我这样做,如果我需要在多个领域建立关系怎么办?例如,X区域中的X模型需要在C-Area中与B区域和C模型中的B模型建立关系吗?我考虑过引入dbContext继承,其中 careadBcontext 将从 bareadbcontext 继承,该从 aareadbcontext 继承,但这会很快破裂。

实体框架是否适合大型数据库应用程序?如果是这样,如何在多个领域管理DBContext?如果没有,而无需编写普通的SQL查询,则可以使用什么?

I am creating a web application on the top of ASP.NET 6 framework. I am trying to figure out the best ORM to use for this project. I am leaning toward Entity Framework for the following reason

  1. I'll be able to use LINQ to write my queries
  2. I'll be able to access my relations easily and directly using native C# model.

Here is where the complication starts. This app will be connecting to a very large database with over 500 tables. Also, the app is going to be broken down into many small logical areas so it's easy for me to maintain it.

If Entity Framework is the way to go, how should I setup the DbContext so I can manage 500+ DbSet and the relations? In other words, should I create a single DbContext for the entire app even when my app is broken down into multiple Areas? Or should I create a DbContext for each area? But if I do that, what if I need to establish relation across multiple areas? For example, X model in X-area need to create a relation to B model in B-area and C model in C-area? I thought about introducing DbContext inheritance where CAreaDbContext would inherit from BAreaDbContext which inherits from AAreaDbContext but that would break real quick.

Is Entity Framework if the right framework for a large database app? If so, how can I manage the DbContext across multiple areas? If not, what would be the alternative to use without having to write plain SQL queries?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自此以后,行同陌路 2025-01-24 09:46:23

EF对于大型数据库非常好。当映射大量表和关系时,第一个查询的单个启动成本是EF初始化并验证其映射的,但这是应用程序的静态成本,而不是每次初始化DBContext。

您可以将应用程序划分为几个DBContexts,以帮助使组织实体更加逻辑并降低那些初始设置成本。如果您想搜索示例,通常将其称为使用有限上下文。这些通常将您的应用程序组织为汇总根或顶级实体,而其他所有内容都属于这些聚合或作为查找等。负责编辑和创建给定实体。

EF和性能领域以及避免有害/意外行为要考虑的最重要的细节是确保您通常不会在实体中加载更多的数据,而不是您需要的。

一些一般建议将包括:

  1. 绝对避免使用EF使用通用存储库模式的诱惑。非传播存储库非常适合促进单位测试或集中重要的,共同的规则/验证,但通用口味导致效率低下且昂贵或过于复杂的代码,通常两者都会同时进行。

  2. 尽可能短。对于Web应用程序,应将其保留不超过请求长度(例如使用IOC容器时)或较短。最坏的情况,使用块使用来范围范围。 DBContext保持活力的越长,它跟踪的实体越多,它跟踪的越多,在加载可能具有导航属性及其获得较慢的其他实体时,通过寻找参考来进行筛选而越多。当您有一个试图保存实体更改的问题时,长期寿命的DBContexts也会“中毒”。这些无效的实体将继续由DBContext跟踪,并干扰未来无关的 savechanges 调用,直到将其删除(分离)或更正。


  3. 使用选择或automapper的 projectto 方法,获得了对投影的理解。加载整个实体图将变得昂贵,尤其是如果剩下DBContext来跟踪所有这些实例。投影到ViewModels/dtos有助于确保只需要加载和传输多大的数据,并使Crystal清楚地传递了什么。 (而不是传递独立实体,或者更糟的是部分填充的独立实体)

  4. 理解 iQueryable 以及LINQ可以为数据提供的一切。 EF查询构建非常有价值,因此您可以利用分类,过滤,分页,投影以及方案来获取计数并检查存在( .yany()()()()()(code>),而无需通过通过大量数据来获取大量数据实体。请参阅第1点以避免陷入此陷阱。


  5. 使用 TOLIST / TolistAsync 很少,请注意,您在Linq Expressions中提供EF的任何逻辑都必须能够转换为SQL。有时,您会发现自己试图构建一个查询,其中EF抱怨它无法评估您的表达。诸如调用私人方法 /未绘制属性之类的东西。在表达式似乎是一个神奇的修复之前,添加 tolist ,迫使客户端评估。这是一个昂贵的操作,因为您有效地获取(通常是跟踪)所有实体,直到那个点,然后继续记忆。对于内存使用而变得昂贵。

  6. 异步方法不是银弹,也不会使查询更快。当您有需要一段时间来运行或经常被称为频繁的查询时,等待异步EF方法非常有用。我的建议是默认使用同步方法,并尽早针对类似于生产的量运行代码。我使用250毫秒作为阈值,但请选择您可以接受的内容并配置您的查询。在这个阈值上面的任何东西都可能受益于异步。通常,诸如搜索之类的东西,尤其是涉及文本匹配搜索的搜索是很好的候选人,因为它们可能有点慢,而且一次通常会有几个用户经常运行。对于在许多用户同时在应用程序过程中可能会经常调用的任何操作也是如此。 async /等待不会使查询更快,它们会使它们稍微慢,但是在查询完成之前不悬挂请求,它们确实会使您的服务器更快地响应。默认情况下使用此功能会使您的代码变得较慢,并且更难进行调试,这没有真正的好处。 (可以很容易地根据需要引入。)

  7. 您的查询配置文件。借助传统数据访问,您将创建模式并编写访问查询(Sprocs等),创建索引。通过EF构建查询,索引变得更像是一个反动过程,您可能会添加典型的索引,但应该查看在类似生产的情况下运行的查询,以根据EF正在构建的高量查询来完善索引。这也提供了对可能渗入查询的其他低效率的关键见解,以及诸如懒惰加载的性能问题。应在可能的情况下对昂贵的查询进行调查和优化。

  8. 准备用排队来进行真正昂贵的查询。系统通常会要求报告和数据导出等问题,或者只是真正昂贵的查询选项。目的是默认设置合理期望。在您需要支持昂贵查询的地方,建立一种机制,允许用户/进程排队查询详细信息作为请求,并雇用背景工作者/池来拾取和处理这些请求。诱惑可能是仅使用 async /等待在这里,但重要的是避免一次启动这些查询中的太多情况。这样的查询将“触摸”许多数据,从而导致系统中的锁和僵局。当看起来一个人没有响应后,用户倾向于反复启动动作,这使问题更加复杂。

EF is perfectly fine for large databases. When mapping a large number of tables and relationships there is a single-time startup cost for the very first query as EF initializes and validates its mapping, but this is a static cost for an application, not each time a DbContext is initialized.

You can split the application across several DbContexts to help make organizing entities more logical and reduce those initial setup costs. This is generally referred to as using Bounded Contexts if you want to search up examples. These typically organize your application down to aggregate roots or top-level entities with everything else falling under those aggregates or serving as lookups, etc. Entities can be registered with multiple DbContexts, though you should aim to ensure that one aggregate root is nominated for being responsible for editing and creating a given entity.

The most important details to consider with EF and areas of performance and avoiding unwanted/unexpected behaviour would be to ensure you generally don't load more data than you need through the entities, more often than you need to.

Some general advice would include:

  1. Absolutely AVOID the temptation to use the Generic Repository pattern with EF. Non-generic Repositories are great to facilitate unit testing or centralize important, common rules/validation, but Generic flavours lead to inefficient and expensive, or overly complex code, usually both.

  2. Keep DbContext lifetimes as short as possible. For Web applications this should be kept no longer than the Request length (when using an IoC container for instance) or shorter. Worst case, use using blocks to scope your DbContext. The longer a DbContext is kept alive, the more entities it tracks, and the more it tracks, the more it needs to sift through looking for references when loading other entities that might have navigation properties and the slower it gets. Long-lived DbContexts can also get "poisoned" when you have an issue attempting to save entity changes. Those invalid entities will remain tracked by the DbContext and interfere with future unrelated SaveChanges calls until they are removed (Detached) or corrected.

  3. Gain an understanding of Projection using Select or AutoMapper's ProjectTo method. Loading entire entity graphs will get expensive, especially if the DbContext is left to track all of those instances. Projection down to ViewModels/DTOs help ensure that only as much data is needed is ever loaded and transmitted and makes it crystal clear what is being passed around. (As opposed to passing detached entities, or worse, partially filled detached entities)

  4. Understand IQueryable and everything that Linq can bring to working with the data. EF query building is extremely valuable, so you can leverage sorting, filtering, pagination, projection, as well as scenarios to get Counts and check existence (.Any()) all without fetching a ton of data via Entities. See point #1 to avoid falling into this trap.

  5. Use ToList/ToListAsync sparingly and be aware that any logic you feed EF in Linq expressions needs to be able to translated down to SQL. Sometimes you will find yourself trying to build a query where EF complains that it cannot evaluate your expression. Things like calling private methods / unmapped properties. Adding a ToList before the expression will seem like a magic fix, forcing a client-side evaluation. This is an expensive operation as you are effectively fetching (and typically tracking) all entities up to that point then continuing in memory. This gets expensive for memory use.

  6. Asynchronous methods are not a silver bullet and does not make queries faster. Awaiting asynchronous EF methods is very useful when you have queries that are going to take a while to run, or be called extremely often. My advice is to default to synchronous methods and test run your code against production-like volumes as early as possible. I use 250ms as a threshold, but pick something acceptable to you and profile your queries. Anything over that threshold is something that would likely benefit from being made asynchronous. Typically things like searches, especially ones that involve text match searches are good candidates as these can be a bit slow and are generally run fairly frequently by several users at a time. The same goes for any operation that might get called a lot through the course of an application by many users at the same time. async/await doesn't make queries faster, they make them slightly slower, but they do make your server more responsive by not hanging the request until the query finishes. Using this by default makes your code a touch slower and a bit tougher to debug for no real benefit. (As it can easily be introduced as needed.)

  7. Profile your queries. With traditional data access you would create your schema and write your access queries (Sprocs etc.) creating indexes as you go. With EF building your queries, indexing becomes more of a reactionary process where you might add your typical indexes, but should look at the queries being run in a production-like scenario to refine indexes based on high-volume queries that EF is building. This also provides key insight into other inefficiencies that might creep into your queries, as well as performance problems like lazy loading being tripped. Expensive queries should be investigated and optimized where possible.

  8. Prepare to employ things like queuing for truly expensive queries. Systems will often call for things like Reports and data exports or just really expensive query options. Aim to set reasonable expectations by default so for instance avoiding things like string Contains() in text searches opting for string StartsWith(). Where you do need to support expensive queries, build a mechanism to allow users/processes to queue the query details as a request and employ a background worker/pool to pick up and process these requests. The temptation might be to just employ async/await here but the important thing is to avoid situations where too many of these queries are kicked off at once. Queries like this will "touch" a lot of data leading to locks and deadlocks in a system. Users have a bad tendency to repeatedly kick off actions when it looks like one isn't responding which compounds the problem on the back-end.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文