Introduction to ABP Series (6): Database Configuration
Copyright © Author: whuanle, reproduction of articles from WeChat public account requires consent from "NCC Open Source Community".
The previous article in this series: https://www.cnblogs.com/whuanle/p/13061059.html
Since this part belongs to the basic section of ASP.NET Core and is not encapsulated by ABP, there’s not much to say.
In this article, we will learn how to add database configurations in ABP and outline a simple database module structure. We will be using EFCore + Freesql to build the database module.
Freesql is highly recommended! Freesql is an ORM framework produced by Teacher Ye and is now a member project of NCC. It has resolved many pain points I face in daily development, and its consideration for business development, along with numerous extensibility features, makes it truly indispensable to me!
In AbpBase.Database
, add the following libraries via Nuget:
All versions are 1.9.0-preview0917; you can use the latest versions.
Freesql
FreeSql.Provider.Sqlite
FreeSql.Provider.SqlServer
FreeSql.Provider.MySql
Creating a Standard EFCore Database Context
In ABP, the EFCore context class needs to inherit from AbpDbContext<T>
, and the overall writing method is consistent with inheriting DbContext<T>
. Next, we will explain step by step how to add EFCore functionality in AbpBase
.
Connection String
In ABP, you can add a ConnectionStringName
attribute to the context class. When configuring services, ABP will automatically configure the connection string for it.
[ConnectionStringName("Default")]
public partial class DatabaseContext : AbpDbContext<DatabaseContext>
Default
is an identifier, and you can use other string identifiers as well.
Defining Isolated Contexts
First, we will create two folders in the AbpBase.Database
module:
BaseData
ExtensionData
The BaseData
directory is used to store contexts for basic table structures, while ExtensionData
is meant for tables that may have extensions or frequently change.
In BaseData, create a class named AbpBaseDataContext
with the following content:
using Microsoft.EntityFrameworkCore;
using Volo.Abp.Data;
using Volo.Abp.EntityFrameworkCore;
namespace AbpBase.Database
{
/// <summary>
/// Context
/// <para>This section is used to define and configure mappings for basic tables</para>
/// </summary>
[ConnectionStringName("Default")]
public partial class AbpBaseDataContext : AbpDbContext<AbpBaseDataContext>
{
#region Define DbSet<T>
#endregion
public AbpBaseDataContext(DbContextOptions<AbpBaseDataContext> options)
: base(options)
{
}
/// <summary>
/// Define mappings
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region Define Mappings
#endregion
OnModelCreatingPartial(modelBuilder);
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
}
In ExtensionData, create an identical AbpBaseDataContext
class with the following content:
using Microsoft.EntityFrameworkCore;
namespace AbpBase.Database
{
public partial class AbpBaseDataContext
{
#region Define DbSet<T>
#endregion
/// <summary>
/// Define mappings
/// </summary>
/// <param name="modelBuilder"></param>
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
}
}
}
The partial class, where the former is used to define those very basic, core entities (tables) and their mappings, and the latter is used to define structures that are likely to undergo multiple modifications during design when some degree of flexibility is felt.
Multi-Database Support and Configuration
Here, we will configure and inject the context so that the program can support multiple databases.
In the AbpBase.Domain.Shared
project, create an enum with the following content:
namespace AbpBase.Domain.Shared
{
public enum AbpBaseDataType
{
Sqlite = 0,
Mysql = 1,
Sqlserver = 2
// Other databases
}
}
Next, create a WholeShared
class with the following content:
namespace AbpBase.Domain.Shared
{
/// <summary>
/// Global shared content
/// </summary>
public static class WholeShared
{
// Database connection properties can be defined in configuration files; here, fixed values are provided just for demonstration.
/// <summary>
/// Database connection string
/// </summary>
public static readonly string SqlConnectString = "";
/// <summary>
/// The type of database to use
/// </summary>
public static readonly AbpBaseDataType DataType = AbpBaseDataType.Sqlite;
}
}
Then, add dependency injection in the ConfigureServices
function of the AbpBaseDatabaseModule
module:
context.Services.AddAbpDbContext<AbpBaseDataContext>();
There’s no need to configure the database connection string here; it can be configured later using some methods provided by ABP.
Configure the context connection string:
string connectString = default;
Configure<AbpDbConnectionOptions>(options =>
{
connectString = WholeShared.SqlConnectString;
options.ConnectionStrings.Default = connectString;
});
Configure multi-database support:
FreeSql.DataType dataType = default;
Configure<AbpDbContextOptions>(options =>
{
switch (WholeShared.DataType)
{
case AbpBaseDataType.Sqlite:
options.UseSqlite<AbpBaseDataContext>(); dataType = FreeSql.DataType.Sqlite; break;
case AbpBaseDataType.Mysql:
options.UseMySQL<AbpBaseDataContext>(); dataType = FreeSql.DataType.MySql; break;
case AbpBaseDataType.Sqlserver:
options.UseSqlServer<AbpBaseDataContext>(); dataType = FreeSql.DataType.SqlServer; break;
}
});
This completes the multi-database configuration for EFCore.
Next, let’s configure Freesql similarly.
Freesql Configuration Service
First, there are several configuration methods within Freesql. Readers can refer to the Wiki to learn about Freesql
: https://github.com/dotnetcore/FreeSql/wiki/%E5%85%A5%E9%97%A8
The author of this article uses a “non-formal” design approach, ha ha ha.
In the BaseData
directory, create a class called FreesqlContext
with the following content:
using FreeSql.Internal;
using System;
using System.Collections.Generic;
using System.Text;
namespace AbpBase.Database
{
/// <summary>
/// Freesql Context
/// </summary>
public partial class FreesqlContext
{
public static IFreeSql FreeselInstance => Freesql_Instance;
private static IFreeSql Freesql_Instance;
public static void Init(string connectStr, FreeSql.DataType dataType = FreeSql.DataType.Sqlite)
{
Freesql_Instance = new FreeSql.FreeSqlBuilder()
.UseNameConvert(NameConvertType.PascalCaseToUnderscore)
.UseConnectionString(dataType, connectStr)
//.UseAutoSyncStructure(true) // Automatically sync entity structures to the database; prohibited in production environments!
.Build();
OnModelCreating(Freesql_Instance);
}
private static void OnModelCreating(IFreeSql freeSql)
{
OnModelCreatingPartial(freeSql);
}
}
}
In the ExtensionData directory, create a FreesqlContext
class with the following content:
using FreeSql;
using System;
using System.Collections.Generic;
using System.Text;
namespace AbpBase.Database
{
public partial class FreesqlContext
{
private static void OnModelCreatingPartial(IFreeSql freeSql)
{
var modelBuilder = freeSql.CodeFirst;
SyncStruct(modelBuilder);
}
/// <summary>
/// Sync structure to the database
/// </summary>
/// <param name="codeFirst"></param>
private static void SyncStruct(ICodeFirst codeFirst)
{
// codeFirst.SyncStructure(typeof(user));
}
}
}
Then, in the ConfigureServices
function of AbpBaseDatabaseModule
, add the injected services:
FreesqlContext.Init(connectString, dataType);
context.Services.AddSingleton(typeof(IFreeSql), FreesqlContext.FreeselInstance);
context.Services.AddTransient(typeof(FreesqlContext), typeof(FreesqlContext));
Through the above steps, our ABP can now support multiple databases, EFCore + Freesql, while isolating the maintenance of tables.
文章评论