在ASP.NET Core应用程序中,我可以像这样通过DI注册DbContext
services.AddDbContext<Models.ShellDbContext>(options => options.UseNpgsql(connection));
知道它的生命周期是什么呢?
从这里https://github.com/aspnet/EntityFramework/blob/f33b76c0a070d08a191d67c09650f52c26e34052/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L140看起来它被配置为Scoped,这意味着每次请求都会创建DbContext实例。
所以问题的第一部分是: 这是真的吗?如果是的话,它的代价是多少?
第二部分是: 如果我创建一个消耗DbContext的服务,并且打算由控制器使用,并且将有一个API来管理DB中的某些实体,那么它是否应该注册为Scoped?
答案 0 :(得分:46)
是的,DbContext
的默认生命周期是作用域。这是这样的。
实例化DbContext
非常便宜,并确保您不会使用许多资源。如果您的DbContext
具有单身生命周期,则DbContext
将跟踪您阅读过的所有记录,除非您专门禁用跟踪。这将需要更多的内存使用,并将继续增长。
DbContext
曲目越多,性能就越低。这就是为什么您经常看到DbContext
仅在using(var context = new AppDbContext())
块中使用的原因。
然而,在Web应用程序中,使用using
块是不好的,因为生命周期由framework管理,如果您将其早期处理,则之后的调用将因异常而失败。
如果您在另一方使用瞬态寿命,您将失去“交易”功能。使用作用域时,DbContext
的事务范围与请求一样长。
如果您需要更细粒度的控制,则必须使用工作单元模式(DbContext
已经使用的模式)。
关于你的第二个问题:
如果您创建服务,它的生命周期必须等于范围或更短的范围(读取:Scoped或瞬态)。
如果您明确需要更长的服务续航时间,则应在服务中注入DbContext
工厂服务或工厂方法。
您可以使用类似
的内容来完成此操作services.AddTransient<Func<AppDbContext>>( (provider) => new Func<MyDbContext>( () => new AppDbContext()));
services.AddSingleton<IMySingletonService, MySingletonService>();
您的服务可能如下所示:
public class MySingletonService : IMySingletonService, IDisposable
{
private readonly AppDbContext context;
public MySingletonService(Func<AppDbContext> contextFactory)
{
if(contextFactory == null)
throw new ArgumentNullException(nameof(contextFactory));
// it creates an transient factory, make sure to dispose it in `Dispose()` method.
// Since it's member of the MySingletonService, it's lifetime
// is effectively bound to it.
context = contextFactory();
}
}
答案 1 :(得分:11)
注意:在EF Core 2中,现在有一个新方法AddDbContextPool
,它创建了一个可以重用的上下文池。范围仍然相同,但实例将被“重置”并返回池中。我原本以为“重置”的开销与创建新的开销相同,但我想情况并非如此。
如果使用此方法,则在请求DbContext实例时 通过控制器,我们将首先检查是否有可用的实例 在游泳池。一旦请求处理完成,就会有任何状态 实例重置,实例本身返回池。+
这在概念上类似于连接池的运作方式 ADO.NET提供商具有节省一些成本的优势 初始化DbContext实例。
https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-2.0#high-performance
答案 2 :(得分:0)
这是我所学到的轶事。这是因为懒惰的KISS热爱。我避免了其他麻烦,并解决了我的过早EF Core DbContext问题,不再考虑池,范围等问题。我只是把不考虑异步返回值的POC放在一起,从控制器链接到存储库,等等。 ,所有这些本质上都返回“ void”,即单数形式的“ Task”。这导致我的DbContext成员在较低例程中进行迭代,从而莫名其妙地处理了基础DbContext。我要做的就是让每个异步方法返回一个def get_batch(image,label,image_W,image_H,batch_size,capacity):
image = tf.cast(image,tf.string)
label = tf.cast(label,tf.int32)
#tf.cast()用来做类型转换
input_queue = tf.train.slice_input_producer([image,label])
#加入队列
label = input_queue[1]
image_contents = tf.read_file(input_queue[0])
image = tf.image.decode_jpeg(image_contents,channels=3,try_recover_truncated = True,acceptable_fraction=0.5)
#jpeg或者jpg格式都用decode_jpeg函数,其他格式可以去查看官方文档
image = tf.image.resize_image_with_crop_or_pad(image,image_W,image_H)
#resize
image = tf.image.per_image_standardization(image)
#对resize后的图片进行标准化处理
image_batch,label_batch = tf.train.batch([image,label],batch_size = batch_size,num_threads=16,capacity = capacity)
label_batch = tf.reshape(label_batch,[batch_size])
image_batch = tf.cast(image_batch,tf.float32)
return image_batch,label_batch
值,并且一切正常。 EF Core不喜欢异步void返回值。