ABP 如何与EFCore集成
- 每个模块定义单独的DbContext类
- 不要在应用程序开发中使用延迟加载
- 不要为DbContext启用延迟加载
DbContext Interface
- 接口继承自IEfCoreDbContext接口
- 添加ConnectionStringName特性到DbContext接口
- 将DbSet
属性添加到DbContext接口中,注意:仅适用于聚合根
DbContext Class
- DbContext类继承自 AbpDbContext
类 - 添加ConnectionStringName 特性到DbContext类
- 实现DbContext接口
[ConnectionStringName("AbpIdentity")]
public class IdentityDbContext : AbpDbContext<IdentityDbContext>, IIdentityDbContext
{
public DbSet<IdentityUser> Users { get; set; }
public DbSet<IdentityRole> Roles { get; set; }
public IdentityDbContext(DbContextOptions<IdentityDbContext> options)
: base(options)
{
}
//code omitted for brevity
}
表前缀与架构
- 添加静态属性 TablePrefix和Schema 到DbContext类,使用常量为其设置一个默认值
public static string TablePrefix { get; set; } = AbpIdentityConsts.DefaultDbTablePrefix;
public static string Schema { get; set; } = AbpIdentityConsts.DefaultDbSchema;
- 要用简短的TablePrefix值为模块在共享数据库中创建不重复的表名
- Schema默认赋值为null
模型映射
- 重写DbContext的OnModelCreating方法显式配置所有实体
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigureIdentity(options =>
{
options.TablePrefix = TablePrefix;
options.Schema = Schema;
});
}
- 不要直接在OnModelCreating方法中配置model ,而是为ModelBuilder定义一个扩展方法 ,使用ConfigureModuleName作为方法名称, 例:
public static class IdentityDbContextModelBuilderExtensions
{
public static void ConfigureIdentity(
[NotNull] this ModelBuilder builder,
Action<IdentityModelBuilderConfigurationOptions> optionsAction = null)
{
Check.NotNull(builder, nameof(builder));
var options = new IdentityModelBuilderConfigurationOptions();
optionsAction?.Invoke(options);
builder.Entity<IdentityUser>(b =>
{
b.ToTable(options.TablePrefix + "Users", options.Schema);
b.ConfigureByConvention();
//code omitted for brevity
});
builder.Entity<IdentityUserClaim>(b =>
{
b.ToTable(options.TablePrefix + "UserClaims", options.Schema);
b.ConfigureByConvention();
//code omitted for brevity
});
//code omitted for brevity
}
}
- 为每个Entity映射调用 b.ConfigureByConvention()
- 通过继承 AbpModelBuilderConfigurationOptions 来创建 configuration Options 类. 例如:
public class IdentityModelBuilderConfigurationOptions : AbpModelBuilderConfigurationOptions
{
public IdentityModelBuilderConfigurationOptions()
: base(AbpIdentityConsts.DefaultDbTablePrefix, AbpIdentityConsts.DefaultDbSchema)
{
}
}
仓储实现
- 从EfCoreRepository<TDbContext,TEntity,TKey> 类继承仓储并实现相应的仓储接口 ,例:
public class EfCoreIdentityUserRepository
: EfCoreRepository<IIdentityDbContext, IdentityUser, Guid>, IIdentityUserRepository
{
public EfCoreIdentityUserRepository(
IDbContextProvider<IIdentityDbContext> dbContextProvider)
: base(dbContextProvider)
{
}
}
- 使用DbContext接口而不是类作为泛型参数
- 使用GetCancellationToken帮助方法将cancellationToken传递给EF Core 例
public virtual async Task<IdentityUser> FindByNormalizedUserNameAsync(
string normalizedUserName,
bool includeDetails = true,
CancellationToken cancellationToken = default)
{
return await DbSet
.IncludeDetails(includeDetails)
.FirstOrDefaultAsync(
u => u.NormalizedUserName == normalizedUserName,
GetCancellationToken(cancellationToken)
);
}
如果调用者代码中未提供取消令牌,则GetCancellationToken会从ICancellationTokenProvider.Token获取取消令牌
- 为具有子集合的聚合根创建 IQueryable
返回类型的 IncludeDetails 扩展方法.
public static IQueryable<IdentityUser> IncludeDetails(
this IQueryable<IdentityUser> queryable,
bool include = true)
{
if (!include)
{
return queryable;
}
return queryable
.Include(x => x.Roles)
.Include(x => x.Logins)
.Include(x => x.Claims)
.Include(x => x.Tokens);
}
- 在仓储其他方法中使用 IncludeDetails 扩展方法, 就像上面的示例代码一样(参阅 FindByNormalizedUserNameAsync).
- 覆盖具有 子集合 的聚合根仓储中的 WithDetails 方法. 例如:
public override IQueryable<IdentityUser> WithDetails()
{
return GetQueryable().IncludeDetails(); // Uses the extension method defined above
}
模块类
- 为Entity Framework Core集成包定义一个Module类.
- 使用 AddAbpDbContext
方法将 DbContext 添加到 IServiceCollection. - 将已实现的仓储添加到 AddAbpDbContext
方法的options中. 例如:
[DependsOn(
typeof(AbpIdentityDomainModule),
typeof(AbpEntityFrameworkCoreModule)
)]
public class AbpIdentityEntityFrameworkCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddAbpDbContext<IdentityDbContext>(options =>
{
options.AddRepository<IdentityUser, EfCoreIdentityUserRepository>();
options.AddRepository<IdentityRole, EfCoreIdentityRoleRepository>();
});
}
}

浙公网安备 33010602011771号