ORM
框架,支持数据库:MySQL
、MariaDB
、TiDB
、OceanBase
、SQL Server
、Oracle
、SQLite
、DuckDB
、MS Access
、Firebird
、PostgreSql
、OpenGauss
、HighgoDB(瀚高)
、IvorySQL
、QuestDB
、DB2
、Informix
、ClickHouse
、Dameng(达梦)
、KingbaseES(人大金仓)
、ShenTong(神通)
、Xugu(虚谷)
DbFirst
、CodeFirst
Expression
表达式树解析:whereExpression
、fieldExpression
Class | Namespace | Description |
---|---|---|
DbFactory |
Sean.Core.DbRepository |
数据库工厂 |
SqlFactory |
Sean.Core.DbRepository |
SQL 创建工厂(CRUD) |
BaseRepository BaseRepository<TEntity> |
Sean.Core.DbRepository |
基于DbFactory 实现 |
DapperBaseRepository DapperBaseRepository<TEntity> |
Sean.Core.DbRepository.Dapper |
基于DbFactory +Dapper 实现 |
Package | NuGet Stable | NuGet Pre-release | Downloads |
---|---|---|---|
Sean.Core.DbRepository | |||
Sean.Core.DbRepository.Dapper |
CRUD Test:
TestRepository.cs
DbFirst:
CodeGeneratorFactory
CodeFirst:
SqlGeneratorFactory
Database | CRUD Test | DbFirst | CodeFirst | Description |
---|---|---|---|---|
MySQL |
✅ | ✅ | ✅ | |
MariaDB |
✅ | ✅ | ✅ | |
TiDB |
✅ | ✅ | ✅ | |
OceanBase |
✅ | ✅ | ✅ | |
SQL Server |
✅ | ✅ | ✅ | |
Oracle |
✅ | ✅ | ✅ | |
SQLite |
✅ | ✅ | ✅ | |
DuckDB |
✅ | ✅ | ✅ | |
MS Access |
✅ | ✅ | ✅ | |
Firebird |
✅ | ✅ | ✅ | |
PostgreSql |
✅ | ✅ | ✅ | |
OpenGauss |
✅ | ✅ | ✅ | |
HighgoDB |
✅ | ✅ | ✅ | 瀚高数据库 |
IvorySQL |
✅ | ✅ | ✅ | |
QuestDB |
✅ | ✅ | ||
DB2 |
✅ | ✅ | ||
Informix |
✅ | ✅ | ||
ClickHouse |
✅ | ✅ | ||
Dameng |
✅ | ✅ | ✅ | 达梦 |
KingbaseES |
✅ | ✅ | 人大金仓 | |
ShenTong |
✅ | ✅ | 神通数据库 | |
Xugu |
✅ | ✅ | 虚谷数据库 |
Dapper
的Execute
方法执行插入批量实体数据的本质是一条一条的插入,当数据量非常大时会很慢,可以分批把多条实体数据拼成一条脚本一次性执行(BulkInsert
)。
PerformanceComparisonTest.CompareBulkInsertTimeConsumed
Operation | 50 Entities | 200 Entities | 1000 Entities | 2000 Entities | 5000 Entities |
---|---|---|---|---|---|
Dapper.Execute |
318 ms | 1401 ms | 5875 ms | 11991 ms | 29968 ms |
BulkInsert |
15 ms | 27 ms | 84 ms | 176 ms | 471 ms |
.NET Framework
:App.config
、Web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<!-- 主库:如果配置了多个数据库,数据库名称后缀是以1开始的数字。 -->
<add name="master" connectionString="DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a" providerName="MySql.Data.MySqlClient"/>
<!-- 从库:如果配置了多个数据库,数据库名称后缀是以1开始的数字。 -->
<add name="secondary1" connectionString="DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a" providerName="MySql.Data.MySqlClient"/>
<add name="secondary2" connectionString="DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a" providerName="MySql.Data.MySqlClient"/>
</connectionStrings>
<appSettings>
</appSettings>
<system.data>
<DbProviderFactories>
<remove invariant="MySql.Data.MySqlClient" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data"/>
</DbProviderFactories>
</system.data>
</configuration>
.NET Core
:appsettings.json
ProviderName
或DatabaseType
的值来指定数据库类型{
"ConnectionStrings": {
// 主库:如果配置了多个数据库,数据库名称后缀是以1开始的数字。
"master": "DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a;ProviderName=MySql.Data.MySqlClient",
// 从库:如果配置了多个数据库,数据库名称后缀是以1开始的数字。
"secondary1": "DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a;ProviderName=MySql.Data.MySqlClient",
"secondary2": "DataSource=127.0.0.1;Database=test;uid=root;pwd=12345!a;ProviderName=MySql.Data.MySqlClient",
"test_SqlServer": "server=127.0.0.1;database=test;uid=sa;pwd=123456!a;DatabaseType=SqlServer",
"test_Oracle": "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=127.0.0.1)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXX)));User ID=XXX;Password=XXX;Persist Security Info=True;DatabaseType=Oracle",
"test_SQLite": "data source=.\\test.db;pooling=True;busytimeout=30000;journal mode=Wal;DatabaseType=SQLite"
}
}
支持2种方式来配置数据库和数据库提供者工厂之间的映射关系:
DatabaseType.MySql.SetDbProviderMap(new DbProviderMap("MySql.Data.MySqlClient", MySqlClientFactory.Instance));// MySql
DatabaseType.SqlServer.SetDbProviderMap(new DbProviderMap("System.Data.SqlClient", SqlClientFactory.Instance));// Microsoft SQL Server
DatabaseType.Oracle.SetDbProviderMap(new DbProviderMap("Oracle.ManagedDataAccess.Client", OracleClientFactory.Instance));// Oracle
DatabaseType.SQLite.SetDbProviderMap(new DbProviderMap("System.Data.SQLite", SQLiteFactory.Instance));// SQLite
DatabaseType.MySql.SetDbProviderMap(new DbProviderMap("MySql.Data.MySqlClient", "MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data"));// MySql
DatabaseType.SqlServer.SetDbProviderMap(new DbProviderMap("System.Data.SqlClient", "System.Data.SqlClient.SqlClientFactory,System.Data.SqlClient"));// Microsoft SQL Server
DatabaseType.Oracle.SetDbProviderMap(new DbProviderMap("Oracle.ManagedDataAccess.Client", "Oracle.ManagedDataAccess.Client.OracleClientFactory,Oracle.ManagedDataAccess"));// Oracle
DatabaseType.SQLite.SetDbProviderMap(new DbProviderMap("System.Data.SQLite", "System.Data.SQLite.SQLiteFactory,System.Data.SQLite"));// SQLite
// 如果直接使用数据库提供者工厂,也可以不配置数据库和数据库提供者工厂之间的映射关系。代码示例:
var db = new DbFactory("Database connection string...", MySqlClientFactory.Instance);// MySql
配置文件路径可以通过
DbContextConfiguration.Options.DbProviderFactoryConfigurationPath
设置
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="dbProviderMap" type="Sean.Core.DbRepository.DbProviderMapSection, Sean.Core.DbRepository" />
</configSections>
<dbProviderMap>
<databases>
<!-- Supports configuring databases that implement the DbProviderFactory class. -->
<database name="MySql" providerInvariantName="MySql.Data.MySqlClient" factoryTypeAssemblyQualifiedName="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data"/>
<database name="MariaDB" providerInvariantName="MySqlConnector.MariaDB" factoryTypeAssemblyQualifiedName="MySqlConnector.MySqlConnectorFactory,MySqlConnector"/>
<database name="TiDB" providerInvariantName="TiDB" factoryTypeAssemblyQualifiedName="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data"/>
<database name="OceanBase" providerInvariantName="OceanBase" factoryTypeAssemblyQualifiedName="MySql.Data.MySqlClient.MySqlClientFactory,MySql.Data"/>
<database name="SqlServer" providerInvariantName="System.Data.SqlClient" factoryTypeAssemblyQualifiedName="System.Data.SqlClient.SqlClientFactory,System.Data"/>
<database name="Oracle" providerInvariantName="Oracle.ManagedDataAccess.Client" factoryTypeAssemblyQualifiedName="Oracle.ManagedDataAccess.Client.OracleClientFactory,Oracle.ManagedDataAccess"/>
<database name="SQLite" providerInvariantName="System.Data.SQLite" factoryTypeAssemblyQualifiedName="System.Data.SQLite.SQLiteFactory,System.Data.SQLite"/>
<database name="DuckDB" providerInvariantName="DuckDB.NET.Data" factoryTypeAssemblyQualifiedName="DuckDB.NET.Data.DuckDBClientFactory,DuckDB.NET.Data"/>
<database name="MsAccess" providerInvariantName="System.Data.OleDb" factoryTypeAssemblyQualifiedName="System.Data.OleDb.OleDbFactory,System.Data"/>
<!--<database name="MsAccess" providerInvariantName="System.Data.Odbc" factoryTypeAssemblyQualifiedName="System.Data.Odbc.OdbcFactory,System.Data"/>-->
<database name="Firebird" providerInvariantName="FirebirdSql.Data.FirebirdClient" factoryTypeAssemblyQualifiedName="FirebirdSql.Data.FirebirdClient.FirebirdClientFactory,FirebirdSql.Data.FirebirdClient"/>
<database name="PostgreSql" providerInvariantName="Npgsql" factoryTypeAssemblyQualifiedName="Npgsql.NpgsqlFactory,Npgsql"/>
<database name="OpenGauss" providerInvariantName="OpenGauss" factoryTypeAssemblyQualifiedName="OpenGauss.NET.OpenGaussFactory,OpenGauss.NET"/>
<database name="HighgoDB" providerInvariantName="HighgoDB" factoryTypeAssemblyQualifiedName="Npgsql.NpgsqlFactory,Npgsql"/>
<database name="IvorySQL" providerInvariantName="IvorySQL" factoryTypeAssemblyQualifiedName="Npgsql.NpgsqlFactory,Npgsql"/>
<database name="QuestDB" providerInvariantName="QuestDB" factoryTypeAssemblyQualifiedName="Npgsql.NpgsqlFactory,Npgsql"/>
<database name="DB2" providerInvariantName="IBM.Data.DB2" factoryTypeAssemblyQualifiedName="IBM.Data.DB2.Core.DB2Factory,IBM.Data.DB2.Core"/>
<database name="Informix" providerInvariantName="IBM.Data.Informix" factoryTypeAssemblyQualifiedName="IBM.Data.Informix.IfxFactory,IBM.Data.Informix"/>
<database name="ClickHouse" providerInvariantName="ClickHouse.Client" factoryTypeAssemblyQualifiedName="ClickHouse.Client.ADO.ClickHouseConnectionFactory,ClickHouse.Client"/>
<database name="Dameng" providerInvariantName="Dameng" factoryTypeAssemblyQualifiedName="Dm.DmClientFactory,DmProvider"/>
<database name="KingbaseES" providerInvariantName="Kdbndp" factoryTypeAssemblyQualifiedName="Kdbndp.KdbndpFactory,Kdbndp"/>
<database name="ShenTong" providerInvariantName="ShenTong" factoryTypeAssemblyQualifiedName="System.Data.OscarClient.OscarFactory,Oscar.Data.SqlClient"/>
<database name="Xugu" providerInvariantName="Xugu" factoryTypeAssemblyQualifiedName="XuguClient.XGProviderFactory,XuguClient"/>
</databases>
</dbProviderMap>
</configuration>
TableEntity
Attribute | Use | Description |
---|---|---|
Sean.Core.DbRepository.CodeFirstAttribute |
Class | 标记为CodeFirst的类 |
System.ComponentModel.DataAnnotations.Schema.TableAttribute |
Class | 设置表名 |
Sean.Core.DbRepository.SequenceAttribute |
Property | 设置序列号名称 (生成自增Id) |
System.ComponentModel.DataAnnotations.KeyAttribute |
Property | 标记为主键字段 |
System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedAttribute |
Property | 设置数据库生成字段值的方式 (通常和 KeyAttribute 一起使用) |
System.ComponentModel.DataAnnotations.Schema.ColumnAttribute |
Property | 设置字段名 |
System.ComponentModel.DescriptionAttribute |
Property | 设置字段描述 |
Sean.Core.DbRepository.NumericAttribute |
Property | 设置数值字段的位数和精度 |
System.ComponentModel.DataAnnotations.MaxLengthAttribute |
Property | 设置字段的最大长度 |
System.ComponentModel.DataAnnotations.RequiredAttribute |
Property | 设置字段不允许为空 |
System.ComponentModel.DefaultValueAttribute |
Property | 设置字段默认值 |
System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute |
Property | 标记为为忽略字段 |
System.ComponentModel.DataAnnotations.Schema.ForeignKeyAttribute |
Property | 标记为外键字段(暂不支持) |
CRUD:
IBaseRepository<TEntity>
// 新增数据:
_testRepository.Add(entity);
// 批量新增数据:
_testRepository.Add(entities);
// 新增或更新数据:
_testRepository.AddOrUpdate(entity);
// 批量新增或更新数据:
_testRepository.AddOrUpdate(entities);
// 删除数据:过滤条件默认为实体的主键字段
_testRepository.Delete(entity);
// 删除数据:自定义过滤条件
_testRepository.Delete(entity => entity.UserId == 10001 && entity.Status != 0);
// 删除全部数据:
_testRepository.Delete(entity => true);
// 删除全部数据:
_testRepository.DeleteAll();
// 更新数据:更新全部字段,过滤条件默认为实体的主键字段
_testRepository.Update(entity);
// 更新数据:更新部分字段,过滤条件默认为实体的主键字段
_testRepository.Update(entity, fieldExpression: entity => new { entity.Status, entity.UpdateTime });
// 更新数据:更新全部字段,自定义过滤条件
_testRepository.Update(entity, whereExpression: entity => entity.UserId == 10001 && entity.Status != 0);
// 更新数据:更新部分字段,自定义过滤条件
_testRepository.Update(entity, fieldExpression: entity => new { entity.Status, entity.UpdateTime }, whereExpression: entity => entity.UserId == 10001 && entity.Status != 0);
// 批量更新数据:更新全部字段,过滤条件默认为实体的主键字段
_testRepository.Update(entities);
// 批量更新数据:更新部分字段,过滤条件默认为实体的主键字段
_testRepository.Update(entities, fieldExpression: entity => new { entity.Status, entity.UpdateTime });
// 数值字段递增:
_testRepository.Increment(10.0M, fieldExpression: entity => entity.AccountBalance, whereExpression: entity => entity.Id == 10001);
// 数值字段递减:
_testRepository.Decrement(10.0M, fieldExpression: entity => entity.AccountBalance, whereExpression: entity => entity.Id == 10001);
// 查询数据:分页 + 排序
int pageNumber = 1;// 当前页号(最小值为1)
int pageSize = 10;// 页大小
OrderByCondition orderBy = OrderByConditionBuilder<TestEntity>.Build(OrderByType.Asc, entity => entity.CreateTime);
orderBy.Next = OrderByConditionBuilder<TestEntity>.Build(OrderByType.Asc, entity => entity.Id);
List<TestEntity> queryResult = _testRepository.Query(entity => entity.UserId == 10001, orderBy, pageNumber, pageSize)?.ToList();
// 查询单个数据:
TestEntity getResult = _testRepository.Get(entity => entity.Id == 2);
// 统计数量:
int countResult = _testRepository.Count(entity => entity.UserId == 10001);
// 数据是否存在:
bool exists = _testRepository.Exists(entity => entity.UserId == 10001);
// 更多使用示例在单元测试中:Sean.Core.DbRepository.Test.TableRepositoryTest
表达式树:
Expression<Func<TEntity, bool>> whereExpression
// 常量
entity => entity.UserId == 10001L
// 变量
entity => entity.UserId == _model.UserId
// bool
entity => entity.IsVip
// bool
entity => !entity.IsVip
// &&
entity => entity.UserId == _model.UserId && entity.AccountBalance < accountBalance
// ||
entity => entity.UserId == _model.UserId || entity.AccountBalance >= accountBalance
// StartsWith
entity => entity.UserId == _model.UserId && entity.Remark.StartsWith("测试")
// 更多使用示例在单元测试中:Sean.Core.DbRepository.Test.WhereExpressionTest
表达式树:
Expression<Func<TEntity, object>> fieldExpression
// 单个字段:
entity => entity.Status
// 多个字段(匿名类型):
entity => new { entity.Status, entity.UpdateTime }
// 更多使用示例在单元测试中:Sean.Core.DbRepository.Test.FieldExpressionTest
OleDb
和ODBC
的区别?
OleDb
是Microsoft开发的一种数据库连接技术,它是面向对象的,可以连接多种类型的数据库,包括Access
、Excel
、SQL Server
等等。OleDb使用COM接口连接数据库,因此只能在Windows平台上使用。ODBC
是一种通用的数据库连接技术,它可以连接多种类型的数据库,包括Access
、Excel
、SQL Server
等等。ODBC使用标准的API连接数据库,因此可以在多个平台上使用,包括Windows、Linux、Unix等等。怎么解决
SQLite
数据库并发读写导致的锁库问题(database is locked)?
问:为什么SQLite并发读写容易出现锁库问题?
答:SQLite使用文件级锁定来管理对数据库的并发访问。这意味着在同一时间,只有一个写操作可以进行,而多个读操作可以并发进行。
SQLite数据库的WAL模式是一种日志机制,它可以减少写入操作时的锁冲突,从而提高并发性能。有以下2种方式启用WAL模式:
方式1:在连接字符串中添加:journal mode=Wal
using System.Data.SQLite;
// 数据库连接字符串
var connStringBuilder = new SQLiteConnectionStringBuilder
{
DataSource = @".\test.db",
Pooling = true,
BusyTimeout = 30000,
JournalMode = SQLiteJournalModeEnum.Wal
};
var connString = connStringBuilder.ConnectionString;// data source=.\test.db;pooling=True;busytimeout=30000;journal mode=Wal
方式2:通过执行SQL命令来设置WAL模式:
-- 查看 SQLite 数据库日志模式:
PRAGMA journal_mode;
-- 设置 SQLite 数据库日志模式:
PRAGMA journal_mode = 'wal';
-- 查看 WAL 文件中未被同步的页面数:
PRAGMA wal_checkpoint;
DbContextConfiguration.Configure(options =>
{
#if UseSqlite
options.SynchronousWriteOptions.Enable = true;// 启用同步写入模式:解决多线程并发写入导致的锁库问题
options.SynchronousWriteOptions.LockTimeout = 30000;// 同步写入锁等待超时时间(单位:毫秒),默认值:10000
options.SynchronousWriteOptions.OnLockTakenFailed = lockTimeout =>
{
Console.WriteLine($"######获取同步写入锁失败({lockTimeout}ms)");
return true;// 返回true:继续执行(仍然可能会发生锁库问题)。返回false:不再继续执行,直接返回默认值
};
#endif
});
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。