GVKun编程网logo

EF DBContext处理不关闭连接(efcore dbcontextpool)

17

在本文中,我们将为您详细介绍EFDBContext处理不关闭连接的相关知识,并且为您解答关于efcoredbcontextpool的疑问,此外,我们还会提供一些关于ABPVnext4.4:统一EfCo

在本文中,我们将为您详细介绍EF DBContext处理不关闭连接的相关知识,并且为您解答关于efcore dbcontextpool的疑问,此外,我们还会提供一些关于ABP Vnext 4.4: 统一 Ef Core 的 DbContext / 移除 EF Core Migrations 项目、AddDbContext was called with configuration, but the context type ''NewsContext'' only decla...、asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)、asp.net – DbContext VS ObjectContext的有用信息。

本文目录一览:

EF DBContext处理不关闭连接(efcore dbcontextpool)

EF DBContext处理不关闭连接(efcore dbcontextpool)

我正在使用EF 6.1.0

我在下面将自定义DBContex对象作为DBEntites

public partial class DbEntities : DbContext
{
    public DbEntities()
        : base("name=DbEntities")
    {
        ////Configuration.LazyLoadingEnabled = true;
        ////Configuration.ProxyCreationEnabled = false;
    }

    //// I have ALL Entites added as below
    ////public virtual IDbSet<CCode> CCodes { get; set; }
}

我对上下文对象执行以下操作

using (var context = new DbEntities())
        {
            var entitySet = context.Set<T>();
            var res = entitySet.Where<T>(predicate).ToList();
            if (context.Database.Connection.State == ConnectionState.Open)
            {
                context.Database.Connection.Close();
            }

            return res;
        }

但是在放置上下文对象之后,我仍然可以看到一个活动的数据库连接。在连接状态下,我可以看到该连接已经关闭(该连接从未为真)。

我正在使用以下查询来查看SQL上的连接。

select db_name(dbid),count(*) 'connections count'
from master..sysprocesses
where spid > 50 and spid != @@spid
group by db_name(dbid)
order by count(*) desc

在下面的语句中,增加了sql连接计数。但是即使处置了它也从未失败过。(我的意思是在使用块计算后,它应该关闭连接)。

var res = entitySet.Where<T>(predicate).ToList();

任何帮助将不胜感激。

ABP Vnext 4.4: 统一 Ef Core 的 DbContext / 移除 EF Core Migrations 项目

ABP Vnext 4.4: 统一 Ef Core 的 DbContext / 移除 EF Core Migrations 项目

Abp vnext 4.4 出现了一个比较重大的变更:在 Startup template 中移除了 EF Core Migrations 项目,本文翻译自 community.abp.io/articl

由于本文发布的时候 Abp vnext 的版本还没有到 4.4,所以本文演示了如何从 4.4 以前的版本移除 EntityFrameworkCore.DbMigrations 这个项目,并且使用唯一的一个 DbContext 来进行数据库的映射和基于 Code-First 模式的迁移。

该项目的 github 地址如下:github.com/abpframework

动机 / 背景

如果你使用 Ef core 作为数据库 provider 创建一个解决方案,那么会有两个与 ef core 有关的项目:

EntityFrameworkCore 这个项目包含了你的应用的真正的 DbContext,它包含了所有的数据库映射和你的 Repository 的实现。

另一方面,EntityFrameworkCore.DbMigrations 项目包含了另一个 DbContext 用来创建和施行数据库迁移。它包含了你所使用的所有模块的数据库映射,所以你有一个单独并统一的数据库架构 / 方案。

当时这么做主要有两个原因:

  1. 你真正的 DbContext 保持了简单和集中(focused)。它只包含了你自己应用中的实体相关的内容并且不包含你所使用的关于其他模块的内容。

  2. 你可以创建自己的类,映射到依赖模块的表。例如,AppUser 实体 (包含在下载的解决方案中) 映射到数据库中的 AbpUsers 表,而 AbpUsers 表实际上映射到 Identity Module 的 IdentityUser 实体。这意味着它们共享相同的数据库表。与 IdentityServer 相比,AppUser 包含的属性更少。您只添加您需要的属性,而不是更多。这还允许您根据自定义需求向 AppUser 添加新的标准 (类型安全) 属性,只要您仔细地管理数据库映射。

对于这个方面的说明我们在官方的文档中有详细的说明。然而,当你重用那些你依赖的模块的表时,会存在一些问题,那就是这样的架构会导致你的数据库映射变得复杂。许多开发者在做一些诸如映射这些类 / 实体的工作时,会变得迷茫和犯错,特别是当他们想要将这些实体和其他实体联系起来时。

所以,我们决定在 4.4 的版本中取消这种分离,删除EntityFrameworkCore.DbMigrations 这个项目。新版本的 abp vnext 中将只包含 EntityFrameworkCore 这个项目并且只拥有一个 DbContext。

如果你今天就想尝试这么干,请接着往下看。

警告

新的设计有一个缺点 (软件开发中的一切都是一种权衡)。我们需要删除 AppUser 实体,因为 EF Core 不能在没有继承关系的情况下将两个类映射到单个表。我将在本文后面介绍这一点,并提供处理它的建议。

步骤

我们的目标是在 EntityFrameworkCore 项目中启用数据库迁移,移除 EntityFrameworkCore.DbMigrations 项目并根据该包重新访问代码。

第一步:为 EntityFrameworkCore 添加 Microsoft.EntityFrameworkCore.Tools 包

在 EntityFrameworkCore.csproj 文件中添加如下代码:

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.*">
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
<PrivateAssets>compile; contentFiles; build; buildMultitargeting; buildTransitive; analyzers; native</PrivateAssets>
</PackageReference>
</ItemGroup>

第二步,创建 design time DbContext factory

在 EntityFrameworkCore 项目中创建一个实现了 IDesignTimeDbContextFactory<T> 的类:

using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
public class UnifiedContextsDemoDbContextFactory : IDesignTimeDbContextFactory<UnifiedContextsDemoDbContext>
{
public UnifiedContextsDemoDbContext CreateDbContext(string[] args)
{
UnifiedContextsDemoEfCoreEntityExtensionMappings.Configure();

var configuration = BuildConfiguration();

var builder = new DbContextOptionsBuilder<UnifiedContextsDemoDbContext>()
.UseSqlServer(configuration.GetConnectionString("Default"));

return new UnifiedContextsDemoDbContext(builder.Options);
}

private static IConfigurationRoot BuildConfiguration()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(Directory.GetCurrentDirectory(), "../UnifiedContextsDemo.DbMigrator/"))
.AddJsonFile("appsettings.json", optional: false);

return builder.Build();
}
}
}

这些代码基本上是从 EntityFrameworkCore.DbMigrations 这个项目中粘贴过来的,重命名了一下并且将里面的 DbContext 替换成了 EntityFrameworkCore 项目中的那个 DbContext。

第三步,创建数据库方案迁移类

EntityFrameworkCore...DbSchemaMigrator(... 代表了你项目的名字)类复制到 EntityFrameworkCore 项目下,并且将其中的 DbContext 替换成 EntityFrameworkCore 项目中的那个真正的 DbContext,在我的示例项目中,代码是这样的:

using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using UnifiedContextsDemo.Data;
using Volo.Abp.DependencyInjection;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
public class EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator
: IUnifiedContextsDemoDbSchemaMigrator, ITransientDependency
{
private readonly IServiceProvider _serviceProvider;

public EntityFrameworkCoreUnifiedContextsDemoDbSchemaMigrator(
IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}

public async Task MigrateAsync()
{
/* We intentionally resolving the UnifiedContextsDemoMigrationsDbContext
* from IServiceProvider (instead of directly injecting it)
* to properly get the connection string of the current tenant in the
* current scope.
*/

await _serviceProvider
.GetRequiredService<UnifiedContextsDemoDbContext>()
.Database
.MigrateAsync();
}
}
}

第四步,转移模块的配置

迁移 DbContext(在迁移项目中定义的那个 DbContext)通常包含你使用的每个模块的 builder.ConfigureXXX () 这样的代码行。我们可以将这些行移动到 EntityFrameworkCore 项目中的实际 DbContext 中。另外,删除 AppUser 的数据库映射 (我们将删除这个实体)。或者,你可以将你自己的实体的数据库映射代码从… DbContextModelCreatingExtensions 类放在实际 DbContext 的 OnModelCreating 方法中,并删除静态扩展类。

注:上文提到的 AppUser 数据库映射这些代码是包含在 EntityFramworkCore 的 DbContext 中,具体如下:

   /* Configure the shared tables (with included modules) here */

builder.Entity<AppUser>(b =>
{
b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser

b.ConfigureByConvention();
b.ConfigureAbpUser();

/* Configure mappings for your additional properties
* Also see the BlazorEfCoreEntityExtensionMappings class
*/
});

最终修改后的 DbContext 是下面这个样子的:

using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.Users;
using Volo.Abp.AuditLogging.EntityFrameworkCore;
using Volo.Abp.BackgroundJobs.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.FeatureManagement.EntityFrameworkCore;
using Volo.Abp.Identity.EntityFrameworkCore;
using Volo.Abp.IdentityServer.EntityFrameworkCore;
using Volo.Abp.PermissionManagement.EntityFrameworkCore;
using Volo.Abp.SettingManagement.EntityFrameworkCore;
using Volo.Abp.TenantManagement.EntityFrameworkCore;

namespace UnifiedContextsDemo.EntityFrameworkCore
{
[ConnectionStringName("Default")]
public class UnifiedContextsDemoDbContext
: AbpDbContext<UnifiedContextsDemoDbContext>
{
public DbSet<AppUser> Users { get; set; }

/* Add DbSet properties for your Aggregate Roots / Entities here.
* Also map them inside UnifiedContextsDemoDbContextModelCreatingExtensions.ConfigureUnifiedContextsDemo
*/

public UnifiedContextsDemoDbContext(
DbContextOptions<UnifiedContextsDemoDbContext> options)
: base(options)
{

}

protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);

builder.ConfigurePermissionManagement();
builder.ConfigureSettingManagement();
builder.ConfigureBackgroundJobs();
builder.ConfigureAuditLogging();
builder.ConfigureIdentity();
builder.ConfigureIdentityServer();
builder.ConfigureFeatureManagement();
builder.ConfigureTenantManagement();

/* Configure your own tables/entities inside here */

//builder.Entity<YourEntity>(b =>
//{
// b.ToTable(UnifiedContextsDemoConsts.DbTablePrefix + "YourEntities", UnifiedContextsDemoConsts.DbSchema);
// b.ConfigureByConvention(); //auto configure for the base class props
// //...
//});
}
}
}

第五步,从解决方案中移除 EntityFrameworkCore.DbMigrations 项目

EntityFrameworkCore.DbMigrations 移除并且将一切引用该项目替换为引用 EntityFrameWorkCore 项目。

同时,EntityFrameworkCore.DbMigrations 项目的作用现在也变更为了 EntityFrameworkCore 项目。

在这个例子中,我需要将 DbMigrator,WebEntityFrameworkCore.Tests 这三个项目的对 EntityFrameworkCore.DbMigrations 的引用变更为 EntityframeworkCore 项目。

第六步,删除 AppUser 实体类

你需要删除 AppUser 实体类,因为 Abp 没有办法在两个没有继承关系的类上面映射同一张表。

所以应该删除它以及和他相关的内容,如果你要查询有关用户的内容,你应该用 IdentityUser 来代替。可以在官方文档中查看与自定义属性和 AppUser 相关的内容。

第七步,创建或者移动迁移内容

现在我们已经删除了 EntityFrameworkCore.DbMigrations 项目。接下来我们要考虑关于数据库迁移的事情了。如果你要保持数据库的迁移历史,你需要从 EntityFrameworkCore.DbMigrations 项目吧 Migrations 目录中的内容拷贝到 EntityFrameworkCore,并且将内容中的 DbContext 手工的替换为 EntityFrameworkCore 项目中定义的 DbContext。

另一种做法是清除项目中的迁移历史,并在数据库中的已提交的迁移历史上继续,那你需要做的是在 EntityFrameworkCore 项目中创建一个数据库迁移,并在该项目的根目录下面执行下面的命令:

dotnet ef migrations add InitialUnified

你无疑需要为这个迁移命令起一个全新的名字,这个迁移肯定会生成一堆内容,你需要小心的将 Up 和 Down 这两个方法中的内容全部删除,然后就可以将这个迁移(实际上是一个空的迁移)应用到数据库了:

dotnet ef database update

这个操作不会对数据库造成任何更改,毕竟你已经将 Up 和 Down 方法里面的内容全删除了。接下来,你就可以像平常一样进行接下来的操作了。

AppUser 实体和自定义扩展属性

现在数据库映射逻辑、解决方案结构、迁移以及我们接下来要做的事情变得更简单了。

作为缺点来说,我们需要删除 AppUser 实体,它和 Identity Module 中定义的 IdentityUser 共享了数据库中的同一张表。幸运的是,当你需要在已存在的实体上(比如 Identity module 中定义的 IdentityUser)增加一些自定义的属性时,Abp 提供了一个相当灵活的系统。在这一节中,我将演示如何在 IdentityUser 上面增加一些自定义的属性,并在程序编码和数据库查询上应用这些自定义的字段。

关于这些内容我已经作为单独的 pr 发布到 github 上,你可以点击这个链接进行查看:

https://github.com/abpframework/abp-samples/pull/89 github.com


声明一个自定义的属性

启动模板中有一个关于在已存在实体上自定义属性的入口,这个入口在 Domain.Share 项目下面,...ModuleExtensionConfigurator.cs(... 代表你项目的名称)这个文件中。打开这个文件并在 ConfigureExtraProperties 方法中下如下代码:

ObjectExtensionManager.Instance.Modules()
.ConfigureIdentity(identity =>
{
identity.ConfigureUser(user =>
{
user.AddOrUpdateProperty<string>( //property type: string
"SocialSecurityNumber", //property name
property =>
{
//validation rules
property.Attributes.Add(new RequiredAttribute());
property.Attributes.Add(new StringLengthAttribute(64));
}
);
});
});

完事儿后,运行程序并在 User table 上面你可以看到这个属性:

新的 SocialSecurityNumber 属性也会在创建和更新 Modal 中显示并应用校验规则。查看如下链接了解关于扩展属性的一切信息:


https://docs.abp.io/en/abp/latest/Module-Entity-Extensions docs.abp.io


映射到数据库表

默认情况下,Abp 将所有自定义的属性保存在数据库表中的 ExtraProperties 属性上,作为一个 JSON 保存 。如果你想要将自定义的字段作为单独的表字段保存,你需要在 EntityFrameworkCore 项目中定义的...EfCoreEntityExtensionMappings.cs 文件(... 代表你项目的名字)上进行编码定义(在 OneTimeRunner.Run 方法中):

ObjectExtensionManager.Instance
.MapEfCoreProperty<IdentityUser, string>(
"SocialSecurityNumber",
(entityBuilder, propertyBuilder) =>
{
propertyBuilder.HasMaxLength(64).IsRequired().HasDefaultValue("");
}
);

这个完事儿后,你需要定义新的数据库迁移方案,将你的新扩展的属性进行迁移(在 EntityframeworkCore 项目下):

dotnet ef migrations add Added_SocialSecurityNumber_To_IdentityUser

这会在 EntityframeworkCore 项目下面新增一个迁移文件,然后你要将这个迁移应用到数据库:

dotnet ef database update

你也可以运行.DbMigrator 项目来应用迁移,这个项目的作用就在于此。

这会在数据库 AbpUsers 表上创建一个 SocialSecurityNumber 字段。

在应用程序代码中使用自定义字段

现在,我们可以在IdentityUser 实体上使用 GetProperty 和 SetProperty 这两个方法来使用我们自定义的属性:

public class MyUserService : ITransientDependency
{
private readonly IRepository<IdentityUser, Guid> _userRepository;

public MyUserService(IRepository<IdentityUser, Guid> userRepository)
{
_userRepository = userRepository;
}

public async Task SetSocialSecurityNumberDemoAsync(string userName, string number)
{
var user = await _userRepository.GetAsync(u => u.UserName == userName);
user.SetProperty("SocialSecurityNumber", number);
await _userRepository.UpdateAsync(user);
}

public async Task<string> GetSocialSecurityNumberDemoAsync(string userName)
{
var user = await _userRepository.GetAsync(u => u.UserName == userName);
return user.GetProperty<string>("SocialSecurityNumber");
}
}
上面的代码中我们使用了”SocialSecurityNumber“硬编码来直接调用,更好的做法是我们可以定义一些扩展方法来包装这种调用。

下面我们改进这种做法:

public static class MyUserExtensions
{
public const string SocialSecurityNumber = "SocialSecurityNumber";

public static void SetSocialSecurityNumber(this IdentityUser user, string number)
{
user.SetProperty(SocialSecurityNumber, number);
}

public static string GetSocialSecurityNumber(this IdentityUser user)
{
return user.GetProperty<string>(SocialSecurityNumber);
}
}

定义后扩展方法后,我们改进一开始的那种调用:

public async Task SetSocialSecurityNumberDemoAsync(string userName, string number)
{
var user = await _userRepository.GetAsync(u => u.UserName == userName);
user.SetSocialSecurityNumber(number); //Using the new extension property
await _userRepository.UpdateAsync(user);
}

public async Task<string> GetSocialSecurityNumberDemoAsync(string userName)
{
var user = await _userRepository.GetAsync(u => u.UserName == userName);
return user.GetSocialSecurityNumber(); //Using the new extension property
}

自定义属性的查询

你可能会基于自定义的属性做一些查询,我们会使用 Entity Framework 的 API 来完成,基于此,我们这里给出两个解决方案:

1、引用 Microsoft.EntityFrameworkCore 包到你的项目中(Domain 项目或者 Application 项目,具体看你的需求)。

2、在 Domain 中创建一个 repository 接口,并在 EntityFrameworkCore 项目中实现它。

我更倾向于第二个方案,所以我在 repository 接口中定义一些方法先:

using System;
using System.Threading.Tasks;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

namespace UnifiedContextsDemo.Users
{
public interface IMyUserRepository : IRepository<IdentityUser, Guid>
{
Task<IdentityUser> FindBySocialSecurityNumber(string number);
}
}

然后在 EntityframeworkCore 项目中实现它:

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using UnifiedContextsDemo.EntityFrameworkCore;
using Volo.Abp.Domain.Repositories.EntityFrameworkCore;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Identity;

namespace UnifiedContextsDemo.Users
{
public class MyUserRepository
: EfCoreRepository<UnifiedContextsDemoDbContext, IdentityUser, Guid>,
IMyUserRepository
{
public MyUserRepository(
IDbContextProvider<UnifiedContextsDemoDbContext> dbContextProvider)
: base(dbContextProvider)
{
}

public async Task<IdentityUser> FindBySocialSecurityNumber(string number)
{
var dbContext = await GetDbContextAsync();
return await dbContext.Set<IdentityUser>()
.Where(u => EF.Property<string>(u, "SocialSecurityNumber") == number)
.FirstOrDefaultAsync();
}
}
}
注意:使用一个常量而不是字符串硬编码来搞这样更好一些。

现在,我们可以在 Service 里面注入 repository 来使用了:)

public class MyUserService : ITransientDependency
{
private readonly IMyUserRepository _userRepository;

public MyUserService(IMyUserRepository userRepository)
{
_userRepository = userRepository;
}

//...other methods

public async Task<IdentityUser> FindBySocialSecurityNumberDemoAsync(string number)
{
return await _userRepository.FindBySocialSecurityNumber(number);
}
}

总结

这篇文章描述了如何删除 EntityFrameworkCore.DbMigrations 项目来简化你的数据库映射、数据库迁移以及应用程序编码。在 4.4 这个版本中,我们已经在启动模板中移除了这个项目了。

源码

https://github.com/abpframework/abp-samples/tree/master/UnifiedEfCoreMigrations

本文分享自微信公众号 - dotNET 跨平台(opendotnet)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

AddDbContext was called with configuration, but the context type ''NewsContext'' only decla...

AddDbContext was called with configuration, but the context type ''NewsContext'' only decla...

问题

An error occurred while starting the application.

ArgumentException: AddDbContext was called with configuration, but the context type ''NewsContext'' only declares a parameterless constructor. This means that the configuration passed to AddDbContext will never be used. If configuration is passed to AddDbContext, then ''NewsContext'' should declare a constructor that accepts a DbContextOptions<NewsContext> and must pass it to the base constructor for DbContext.
Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CheckContextConstructors<TContext>()

ArgumentException: AddDbContext was called with configuration, but the context type ''NewsContext'' only declares a parameterless constructor. This means that the configuration passed to AddDbContext will never be used. If configuration is passed to AddDbContext, then ''NewsContext'' should declare a constructor that accepts a DbContextOptions<NewsContext> and must pass it to the base constructor for DbContext.
Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CheckContextConstructors<TContext>()
Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.AddDbContext<TContextService, TContextImplementation>(IServiceCollection serviceCollection, Action<IServiceProvider, DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime)
Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.AddDbContext<TContextService, TContextImplementation>(IServiceCollection serviceCollection, Action<DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime)
Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.AddDbContext<TContext>(IServiceCollection serviceCollection, Action<DbContextOptionsBuilder> optionsAction, ServiceLifetime contextLifetime, ServiceLifetime optionsLifetime)
News.Startup.ConfigureServices(IServiceCollection services) in Startup.cs
+
            services.AddDbContext<NewsContext>(options =>
Microsoft.AspNetCore.Hosting.ConventionBasedStartup.ConfigureServices(IServiceCollection services)
Microsoft.AspNetCore.Hosting.Internal.WebHost.EnsureApplicationServices()
Microsoft.AspNetCore.Hosting.Internal.WebHost.Initialize()
Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

 

 

 

原因

NewsContext.cs

using Microsoft.EntityFrameworkCore;

namespace News.Service
{
    public class NewsContext : DbContext
    {
        public DbSet<News.Model.Entity.News> News { get; set; }
        public DbSet<News.Model.Entity.Banner> Banner { get; set; }
        public DbSet<News.Model.Entity.Comment> Comment { get; set; }
        public DbSet<News.Model.Entity.NewsClassify> NewsClassify { get; set; }
    }
}

 

Startup.cs

public void ConfigureServices(IServiceCollection services)
        {
            ......

            services.AddDbContext<NewsContext>(options =>
            {
              options.UseSqlServer(Configuration.GetConnectionString("MsSqlConnection"), db => db.UseRowNumberForPaging());
            });

            ......

        }

 

该错误表示,如果通过 AddDbContext 配置 NewsContext,那么需要添加一个 DbContextOptions<NewsContext> 类型参数的构造函数到 NewsContext 类。否则.net core 不能注入时带上 AddDbContext 添加的配置

 

解决方法

如上面所说,NewsContext 类添加一个 DbContextOptions<NewsContext> 类型参数的构造函数

using Microsoft.EntityFrameworkCore;

namespace News.Service
{
    public class NewsContext : DbContext
    {
        public NewsContext(DbContextOptions<NewsContext> options) : base(options)
        {
        }

        public DbSet<News.Model.Entity.News> News { get; set; }
        public DbSet<News.Model.Entity.Banner> Banner { get; set; }
        public DbSet<News.Model.Entity.Comment> Comment { get; set; }
        public DbSet<News.Model.Entity.NewsClassify> NewsClassify { get; set; }
    }
}

 

asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

原文: asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)

一.连接字符串

  在上二篇中,ASP.NET Core 应用程序连接字符串是写死在ConfigureServices代码中,下面介绍通过配置来实现。连接字符串可以存储在 appsettings.json、用户机密存储、其他配置源中。 下面示例演示appsettings.json 中存储的连接字符串,这样不管asp.net core在什么环境(Development、Staging 、Production)都能调用该文件。

"ConnectionStrings": {
    "BloggingDatabase": "Data Source = {ip};Initial Catalog = EFGetStarted.AspNetCore.NewDb; User ID = hsr;Password =js*2015;"
  },

   通常在Startup.cs读取连接字符串。 使用GetConnectionString()方法查找配置值,该查询的格式:ConnectionStrings:<connection string name>其中键是connection

// var connection = "Data Source = {ip}; Initial Catalog = EFGetStarted.AspNetCore.NewDb; User ID = hsr;Password =js*2015;";
      var connection = Configuration.GetConnectionString("BloggingDatabase");
      services.AddDbContext<EFGetStartedAspNetCoreNewDbContext>(options => options.UseSqlServer(connection));

  

二. 连接复原

  可以通过策略,自动重试已失败的数据库命令,通过提供“执行策略”,它封装检测故障,然后重试命令所需的逻辑,该功能可以应用于任何数据库。例如: SQL Server 提供程序,包括专门针对 SQL Server (包括 SQL Azure) 的执行策略。 它知道可以重试的异常类型,并且具有合理的默认值的最大重试,重试次数等之间的延迟。为上下文配置选项时将指定执行策略。 这通常位于派生上下文的 OnConfiguring 方法中,或位于 ASP.NET Core 应用程序的 Startup.cs 中。通过EnableRetryOnFailure方法参数重载,可以自定义设置失败故障重试次数

//(1)配置在Startup.cs 中设置连接复原。
    var connection = Configuration.GetConnectionString("BloggingDatabase");
        services.AddDbContext<EFGetStartedAspNetCoreNewDbContext>
                (options => { options.UseSqlServer(connection,sqlServerOptions=> sqlServerOptions.EnableRetryOnFailure()); });

   //(2)配置在EF上下文的OnConfiguring方法中,设置连接复原
   protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    optionsBuilder
        .UseSqlServer(
            @"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True;ConnectRetryCount=0",
            options => options.EnableRetryOnFailure());
    }

  

  2.1 执行策略和事务

    在出现故障时自动重试的执行策略需要能够回滚失败的重试块中的每个操作。启用重试后,通过 EF Core 执行的每个操作都将成为其自身的可重试操作。也就是说,如果出现暂时性故障,每个查询和对 SaveChanges() 的每次调用都将作为一个单元进行重试。

    如果代码使用 BeginTransaction() 启动事务(设置sql事务),定义了自己的操作组(这些操作需要被视为一个单元)。如果发生故障,将需要回滚事务内的所有内容。 如果尝试在使用执行策略时执行此操作(发生故障重试),将收到如下所示的异常:"InvalidOperationException: 配置的执行策略 SqlServerRetryingExecutionStrategy 不支持用户启动的事务"

    解决方法:手动调用执行策略,委托中放入需要执行的所有内容。 如果发生暂时性故障,执行策略将再次调用委托。

//using Microsoft.EntityFrameworkCore; 
            using (var db = new EFGetStartedAspNetCoreNewDbContext())
            {
                var strategy = db.Database.CreateExecutionStrategy();

                strategy.Execute(() =>
                {
                    using (var context = new EFGetStartedAspNetCoreNewDbContext())
                    {
                        using (var transaction = context.Database.BeginTransaction())
                        {
                            context.Blogs.Add(new Blogs { Url = "http://blogs.msdn.com/dotnet" });
                            context.SaveChanges();

                            context.Blogs.Add(new Blogs { Url = "http://blogs.msdn.com/visualstudio" });
                            context.SaveChanges();

                            transaction.Commit();
                        }
                    }
                });
            }

  

三. 配置 DbContext介绍

  下面简单介绍 DbContextOptions 配置 DbContext, 以使用特定的 EF Core 提供程序(数据库提供程序)和可选行为来连接到数据库的基本模式。DbContext配置是通过如:migrations命令来完成(migrations使用在asp.net core 系列 20中有讲到)。该工具能够发现和创建 DbContext 类型的工作实例,收集有关应用程序实体类型及其如何映射到数据库架构的详细信息。这些过程都可以自动执行。

  DbContext 必须具有 DbContextOptions 的实例才能执行工作。对于DbContextOptions 实例包含如下配置信息: 

    (1) 数据库提供程序 。如使用Microsoft.EntityFrameworkCore.SqlServer提供程序,将提供扩展方法DbContextOptionsBuilder.UseSqlServer。如使用Microsoft.EntityFrameworkCore.Sqlite,将提供扩展方法DbContextOptionsBuilder. UseSqlite。这些扩展方法需要相应的提供程序包。

    (2) 必要的数据库连接字符串,作为参数传递到上面讲到的扩展方法中, 如SqlServer 使用DbContextOptionsBuilder.UseSqlServer(connection

    (3) 任何提供程序级别的可选行为选择器,是针对特定的数据库提供程序。如Microsoft.EntityFrameworkCore.SqlServer, 使用SqlServerDbContextOptionsBuilder可选行为选择器。

    (4) 任何通用EF Core行为选择器,不针对数据库提供程序。services.AddDbContext 方法中参数Action<DbContextOptionsBuilder>来调用。

 

  下面的示例将配置DbContextOptions使用SQL Server 提供程序,包含必要的数据库连接字符串connection变量、 提供程序级别的命令超时CommandTimeout,以及使用通用EF Core行为选择器UseQueryTrackingBehavior在执行的EF所有查询中不跟踪:

var connection = Configuration.GetConnectionString("BloggingDatabase");
            services.AddDbContext<EFGetStartedAspNetCoreNewDbContext>
                (options =>
                {
                    //sqlServerOptions数据库提供程序级别的可选行为选择器
                    //UseQueryTrackingBehavior 为通用EF Core行为选择器
                    options.UseSqlServer(connection, sqlServerOptions =>
                    {
                        sqlServerOptions.EnableRetryOnFailure();
                        sqlServerOptions.CommandTimeout(60);
                    })
                    .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
                });

 

 

 参考文献:

    官方资料:ASP.NET Core 连接字符串

           ASP.NET Core 连接复原

           ASP.NET Core 配置 DbContext

           migrations迁移介绍

设置连接复原

asp.net – DbContext VS ObjectContext

asp.net – DbContext VS ObjectContext

我曾经使用DbContext为我的所有数据库模型,直到我读了 Ways to optimize Entity Framework,在按照我发现自己被迫切换到ObjectContext的步骤之后,所以,有很多代码更改要做,但我不确定我做了正确的事情,特别是在谷歌搜索后,我注意到DbContext比ObjectContext更新更好,而且我注意到我在转换到像“迁移”和“查找”方法之类的ObjectContext时丢失了很多东西等等…

那么,通过预生成视图来改变我的代码以使用ObjectContext而不是DbContext来提高速度是正确的吗?或者我做错了什么?

解决方法

您不必切换到ObjectContext以获取预生成的视图.我创建了T4模板,用于为CodeFirst生成预生成的视图.看看这里: Entity Framework initialization is SLOW — what can I do to bootstrap it faster?
Visual Studio gallerry上提供了T4模板.这是 link到我的博客文章,描述了如何获取和使用它们

今天关于EF DBContext处理不关闭连接efcore dbcontextpool的介绍到此结束,谢谢您的阅读,有关ABP Vnext 4.4: 统一 Ef Core 的 DbContext / 移除 EF Core Migrations 项目、AddDbContext was called with configuration, but the context type ''NewsContext'' only decla...、asp.net core 系列 22 EF(连接字符串,连接复原,DbContext)、asp.net – DbContext VS ObjectContext等更多相关知识的信息可以在本站进行查询。

本文标签:

上一篇使用Python的交互式输入/输出(python 交互输入)

下一篇Python:不按字典顺序对字符串编号进行排序(python字典按字母排序)