首页 > 其他 > 详细

ABP 如何与EFCore集成

时间:2020-08-19 09:57:25      阅读:186      评论:0      收藏:0      [点我收藏+]
  • 每个模块定义单独的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>();
        });
    }
}

ABP 如何与EFCore集成

原文:https://www.cnblogs.com/pelva/p/13527460.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!