MiD*_*Daa 16 c# entity-framework-core .net-core
当我的表由另一方更新时,dotnet核心中的db上下文仍然返回旧值,如何强制Db上下文刷新?
我已经完成了研究,但我只发现人们使用ReloadEF核心无法使用的方法来强制刷新上下文.
其他一些解决方案建议在使用后配置上下文,但是我得到错误说DB上下文是通过依赖注入创建的,我不应该搞砸它.
bin*_*nki 12
您提到当您尝试重新创建时DbContext,您会收到有关由依赖注入(DI)系统管理的上下文的错误.使用依赖注入系统进行对象创建有两种不同的样式.DI可以创建一个全局单例实例,该实例在所有使用者之间作为服务共享,也可以为每个作用域/工作单元创建一个实例(例如,在Web服务器中按请求).
如果您的DI系统配置为创建单个全局共享实例DbContext,那么您将遇到与长期相关的各种问题DbContext.DbContext按照设计,永远不会自动从缓存中删除对象,因为它的设计并不长久.因此,长寿DbContext会浪费内存.此外,您的代码永远不会看到加载到其缓存中的项目的更改,而无需手动重新加载它加载的每个实体.因此,最佳做法是DbContext每单位工作使用一个.您的DI系统可以通过配置为应用程序在范围内处理的每个请求提供新的实例来帮助您解决此问题.例如,ASP.NET Core的依赖注入系统支持按请求确定范围.
获取新数据的最简单方法是创建一个新数据DbConcurrencyException.但是,在您的工作单元内,或在DI系统提供的作用域粒度限制范围内,您可能会触发一个外部进程,该进程应该直接在数据库中修改您的实体.在退出DI范围或完成工作单元之前,您可能需要查看更改.在这种情况下,您可以通过分离数据对象的实例来强制重新加载.
要做到这一点,首先得到DbContext你的对象.这是一个允许您操作DbContext该对象的内部缓存的对象.然后,您可以通过设置EntityEntry<>其DbContext属性来标记此条目.我相信这EntitytState.Detached会将条目留在缓存中,但会导致在将来实际加载条目时删除并替换它.重要的是它会导致将来的加载将新加载的实体实例返回到您的代码中.例如:
var thing = context.Things.Find(id);
if (thing.ShouldBeSentToService) {
TriggerExternalServiceAndWait(id);
// Detach the object to remove it from context’s cache.
context.Entities(thing).State = EntityState.Detached;
// Then load it. We will get a new object with data
// freshly loaded from the database.
thing = context.Things.Find(id);
}
UseSomeOtherData(thing.DataWhichWasUpdated);
Run Code Online (Sandbox Code Playgroud)
随着 .NET 5.0 和 Entity Framework Core 5.0 的发布,推荐的模式是使用DBContext 工厂。在 Statup.cs 中我改变了:
services.AddDbContext<MyDbContext>...
Run Code Online (Sandbox Code Playgroud)
到
services.AddDbContextFactory<MyDbContext>...
Run Code Online (Sandbox Code Playgroud)
我的所有存储库类都使用相同的基类,这里我在构造函数中创建上下文:
protected BaseRepository(IDbContextFactory<MyDbContext> contextFactory)
{
_context = contextFactory.CreateDbContext();
}
Run Code Online (Sandbox Code Playgroud)
我使用一个非常简单的存储库工厂来确保每次需要时都能获得存储库和 dbcontext 的新实例:
using System;
using Data.Models.Entities;
using Microsoft.Extensions.DependencyInjection;
namespace Data.Repository
{
public class RepositoryFactory : IRepositoryFactory
{
private readonly IServiceProvider _serviceProvider;
public RepositoryFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IApplicationRepository BuildApplicationRepository()
{
var service = _serviceProvider.GetService<IApplicationRepository>();
return service;
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用所描述的模式可以解决“数据库上下文是通过依赖注入创建的”错误,并且不需要 Reload()/Refresh() 方法。
哦,这个问题困扰了我好几天。
我将Visual Studio 2017与.Net Core 2.1结合使用,我的EF Core代码看起来像这样:
// 1. Load a [User] record from our database
int chosenUserID = 12345;
User usr = dbContext.Users.FirstOrDefault(s => s.UserID == chosenUserID);
// 2. Call a web service, which updates that [User] record
HttpClient client = new HttpClient()
await client.PostAsync("http://someUrl", someContent);
// 3. Attempt to load an updated copy of the [User] record
User updatedUser = dbContext.Users.FirstOrDefault(s => s.UserID == chosenUserID);
Run Code Online (Sandbox Code Playgroud)
在第3步中,只需将“ updatedUser”设置为[User]记录的原始版本,而不是尝试加载新副本。因此,如果在步骤3之后,我修改了该[User]记录,那么实际上我将丢失该Web服务对其应用的任何设置。
我-最终-找到了两个解决方案。
我可以更改ChangeTracker设置。这行得通,但是我担心这样做的副作用:
dbContext.ChangeTracker.QueryTrackingBehavior = Microsoft.EntityFrameworkCore.QueryTrackingBehavior.NoTracking;
Run Code Online (Sandbox Code Playgroud)
或者,在尝试重新加载[User]记录之前,我可以插入以下命令...
await dbContext.Entry(usr).ReloadAsync();
Run Code Online (Sandbox Code Playgroud)
这似乎迫使.Net Core重新加载该[User]记录,并且生活再次美好。
我希望这是有用的...
跟踪并修复此错误花了我几天的时间。
还有描述不同的方式来解决这个缓存的问题一个很好的文章在这里。
Reload并且ReloadAsync从那时起就可以使用Entity Framework Core 1.1
例子:
//test.Name is test1
var test = dbContext.Tests.FirstOrDefault();
test.Name = "test2";
//test.Name is now test1 again
dbContext.Entry(test).Reload();
Run Code Online (Sandbox Code Playgroud)
小智 5
这个简单的序列刷新了 EFCore 5.0 下的整个上下文:
public void Refresh()
{
(Context as DbContext).Database.CloseConnection();
(Context as DbContext).Database.OpenConnection();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12738 次 |
| 最近记录: |