作者 Mr-zhong
开源项目地址 https://github.com/China-Mr-zhong/Fast.Framework
QQ交流群 954866406 欢迎小伙伴加入交流探讨技术
Fast Framework 是一个基于NET6.0 封装的轻量级 ORM 框架 支持多种数据库 SqlServer Oracle MySql PostgreSql Sqlite
优点: 体积小、可动态切换不同实现类库、原生支持微软特性、流畅API、使用简单、性能高、模型数据绑定采用 委托+缓存、强大的表达式解析、子查询的原生支持、复杂表达式含成员变量解析,解析性能是目前常见框架中 No1 主要是有缓存的支持 、源代码可读性强。
缺点:目前仅支持Db Frist Code Frist 暂时不考虑 主要是需要花费大量时间和精力。
名称
说明
Fast.Framework
接口实现类库(框架核心接口实现)
Fast.Framework.Aop
Aop类库(基于微软DispatchProxy抽象类封装)
Fast.Framework.Extensions
扩展类库(主要扩展框架核心方法,方便使用)
Fast.Framework.Interfaces
接口类库(框架核心接口定义)
Fast.Framework.Logging
日志类库(主要实现自定义文件日志)
Fast.Framework.Models
模型 框架所用到的实体类
Fast.Framework.Utils
工具类库
Fast.Framework.Test
控制台终端测试项目
Fast.Framework.UnitTest
单元测试项目
Fast.Framework.Web.Test
Web测试项目
Ado 原生Ado对象
IAdo ado = new AdoProvider(new DbOptions()
{
DbId = "1",
DbType = DbType.MySQL,
ProviderName = "MySqlConnector",
FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector",
ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout=30;"
});
DbContext 支持多租户 支持切换不同Ado实现类库 设置 ProviderName和FactoryName 即可
IDbContext db = new DbContext(new List
new DbOptions()
{
DbId = "1",
DbType = DbType.MySQL,
ProviderName = "MySqlConnector",
FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector",
ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout=30;"
}});
依赖注入
// 注册服务
builder.Services.AddScoped<IDbContext, DbContext>();
// 数据库选项支持Options接口注入 不是很理解的可以看代码实现
builder.Services.Configure<List<DbOptions>>(configuration.GetSection("DbConfig"));
// 产品服务类 通过构造方法注入
public class ProductService
{
/// <summary>
/// 数据库
/// </summary>
private readonly IDbContext db;
/// <summary>
/// 构造方法
/// </summary>
/// <param name="db">数据库</param>
public ProductService(IDbContext db)
{
this.db = db;
}
}
实体对象插入
var product = new Product()
{
ProductCode = "1001",
ProductName = "测试商品1"
};
var result = await db.Insert(product).ExceuteAsync();
Console.WriteLine($"实体对象插入 受影响行数 {result}");
实体对象插入并返回自增ID 仅支持 SQLServer MySQL SQLite
var product = new Product()
{
ProductCode = "1001",
ProductName = "测试产品1"
};
var result = await db.Insert(product).ExceuteReturnIdentityAsync();
Console.WriteLine($"实体对象插入 返回自增ID {result}");
实体对象列表插入
var list = new List
for (int i = 0; i < 2100; i++)
{
list.Add(new Product()
{
ProductCode = $"编号{i + 1}",
ProductName = $"名称{i + 1}"
});
}
var result = await db.Insert(list).ExceuteAsync();
Console.WriteLine($"实体对象列表插入 受影响行数 {result}");
匿名对象插入
var obj = new
{
ProductCode = "1001",
ProductName = "测试商品1"
};
//注意:需要使用As方法显示指定表名称
var result = await db.Insert(obj).As("product").ExceuteAsync();
Console.WriteLine($"匿名对象插入 受影响行数 {result}");
匿名对象列表插入
var list = new List
字典插入
var product = new Dictionary
{
{"ProductCode","1001"},
{ "ProductName","测试商品1"}
};
//注意:需要显示指定类型否则无法重载到正确的方法,如果没有实体类型可用object类型并配合As方法显示指定表名称.
var result = await db.Insert
Console.WriteLine($"字典插入 受影响行数 {result}");
字典列表插入
var list = new List
for (int i = 0; i < 2100; i++)
{
list.Add(new Dictionary
{
{"ProductCode","1001"},
{ "ProductName","测试商品1"}
});
}
//注意:需要显示指定泛型类型否则无法重载到正确的方法,如果没有实体可用object类型并配合As方法显示指定表名称.
var result = await db.Insert
Console.WriteLine($"字典列表插入 受影响行数 {result}");
实体对象删除
var product = new Product()
{
ProductId = 1,
ProductCode = "1001",
ProductName = "测试商品1"
};
//注意:必须标记KeyAuttribute特性 否则将抛出异常
var result = await db.Delete(product).ExceuteAsync();
Console.WriteLine($"实体删除 受影响行数 {result}");
无条件删除
var result = await db.Delete
Console.WriteLine($"无条件删除 受影响行数 {result}");
表达式删除
var result = await db.Delete
Console.WriteLine($"条件删除 受影响行数 {result}");
特殊删除
//特殊用法 如需单个条件或多个可搭配 WhereColumn或WhereColumns方法
var result = await db.Delete
实体对象更新
var product = new Product()
{
ProductId = 1,
ProductCode = "1001",
ProductName = "测试商品1"
};
//注意:标记KeyAuttribute特性属性或使用Where条件,为了安全起见全表更新将必须使用Where方法
var result = await db.Update(product).ExceuteAsync();
Console.WriteLine($"对象更新 受影响行数 {result}");
指定列更新
var result = await db.Update
.Columns("ProductCode", "ProductName").ExceuteAsync();
// 字段很多的话可以直接new List
忽略列更新
var result = await db.Update
.IgnoreColumns("Custom1").ExceuteAsync();
// 同上使用方法一样
实体对象列表更新
var list = new List
for (int i = 0; i < 2022; i++)
{
list.Add(new Product()
{
ProductCode = $"编号{i + 1}",
ProductName = $"名称{i + 1}"
});
}
//注意:标记KeyAuttribute特性属性或使用WhereColumns方法指定更新条件列
var result = await db.Update(list).ExceuteAsync();
Console.WriteLine($"对象列表更新 受影响行数 {result}");
匿名对象更新
var obj = new
{
ProductId = 1,
ProductCode = "1001",
ProductName = "测试商品1"
};
//注意:需要显示指定表名称 以及更新条件 使用 Where或者WhereColumns方法均可
var result = await db.Update(obj).As("product").WhereColumns("ProductId").ExceuteAsync();
Console.WriteLine($"匿名对象更新 受影响行数 {result}");
匿名对象列表更新
var list = new List
字典更新
var product = new Dictionary
{
{ "ProductId",1},
{"ProductCode","1001"},
{ "ProductName","测试商品1"}
};
//注意:需要显示指定泛型类型否则无法重载到正确的方法并且使用WhereColumns方法指定条件列
var result = await db.Update
Console.WriteLine($"字典更新 受影响行数 {result}");
字典列表更新
var list = new List
for (int i = 0; i < 2022; i++)
{
list.Add(new Dictionary
{
{ "ProductId",i+1},
{"ProductCode",$"更新编号:{i+1}"},
{ "ProductName",$"更新商品:{i + 1}"}
});
}
//注意:需要显示指定泛型类型否则无法重载到正确的方法并且使用WhereColumns方法执行条件列
var result = await db.Update
Console.WriteLine($"字典列表更新 受影响行数 {result}");
表达式更新
var product = new Product()
{
ProductId = 1,
ProductCode = "1001",
ProductName = "测试商品1"
};
var result = await db.Update(product).Where(p => p.ProductId == 100).ExceuteAsync();
Console.WriteLine($"表达式更新 受影响行数 {result}");
单一查询
var data = await db.Query
列表查询
var data = await db.Query
返回单个字典
var data = await db.Query
返回字典列表
var data = await db.Query
分页查询
var page = new Pagination() { Page = 1, PageSize = 100 };
var data = await db.Query
计数查询
var data = await db.Query
任何查询
var data = await db.Query
条件查询
var data = await db.Query
//需要调用返回数据结果的方法 例如:ToListAsync
Like 查询
var data = await db.Query
Not Like查询
var data = await db.Query
//由于没有专门去扩展 Not Like 方法,可以用取反或使用比较变通实现 例如 w.ProductName.StartsWith("左模糊")==false
//Mysql举例 最终解析后的结果为 ProductName
Like '%左模糊' = 0 这种用法数据库是支持的 相当于 Not Like
Select查询 (选择字段)
var data = await db.Query
{
s.ProductId,
s.ProductName
}).ToListAsync();
分组查询
var data = await db.Query
{
s.ProductId,
s.ProductName
}).ToListAsync();
分组聚合查询
var sql = db.Query
{
a.OrderCode
}).Select((a, b) => new
{
a.OrderCode,
Sum_Qty = SqlFunc.Sum(b.Qty)//支持嵌套
}).ToListAsync();
排序查询
var data = await db.Query
{
s.CreateTime
}).ToListAsync();
//这是多个字段排序使用方法 还有其它重载方法
Having查询
var data = await db.Query
{
s.ProductId,
s.ProductName
}).Having(s => SqlFunc.Count(s.ProductId) > 1).ToListAsync();
//必须先使用GroupBy方法 懂得都懂
联表查询
var data = await db.Query
LeftJoin
// 右连接对应的是 RightJoin 内连接对应 InnerJoin
联合查询
var query1 = db.Query
var query2 = db.Query
db.Union(query1, query2);//联合
db.UnionAll(query1, query2);//全联合
//执行查询调用Toxx方法
查询并插入 仅支持同实例的数据库 跨库 个人还是建议 用事务分开写查询和插入
//方式1
var result1 = await db.Query
{
s.ProductCode,
s.ProductName
}).Insert
{
p.ProductCode,
p.ProductName
});
//方式2 需要注意的是 显示指定不带 列标识符 例如 列名称1
如有字段冲突 可自行加上标识符
var result2 = await db.Query
{
s.ProductCode,
s.ProductName
}).Insert("表名称 同实例不同库 可以使用 db.数据库名称.表名称 ", "列名称1", "列名称2", "带标识的列名称3
");
//方式3 需要注意同方式2 一样
var result3 = await db.Query
{
s.ProductCode,
s.ProductName
}).Insert("表名称 同实例不同库 可以使用 db.数据库名称.表名称 ", new List
In查询
// 方式1
var data1 = await db.Query
// 方式2
var data2 = await db.Query
// 方式3 需要动态更新IN值 使用这种
var list = new List
var data3 = await db.Query
// 方法4 参数同上一样 单独分离IN和NotIN 是为了兼容匿名查询
var data4 = await db.Query
子查询
var subQuery = db.Query
var sql1 = db.Query
{
Custom1 = db.SubQuery
}).ToListAsync();
// 这种没有使用new 的 泛型可随意定义 实际作用就是避免 对象属性赋值类型冲突的问题
var sql2 = db.Query
高性能表达式动态缓存的支持
var list = new List
Expression
for (int i = 1; i <= 3; i++)
{
list.Add($"动态添加参数{i}");
var stopwatch1 = new Stopwatch();
stopwatch1.Start();
var result = ex.ResolveSql(new ResolveSqlOptions()
{
DbType = Models.DbType.MySQL,
ResolveSqlType = ResolveSqlType.Where
});
stopwatch1.Stop();
Console.WriteLine($"解析耗时:{stopwatch1.ElapsedMilliseconds}ms {stopwatch1.ElapsedMilliseconds / 1000.00}s 解析Sql字符串:{result.SqlString}");
}
解析结果
解析耗时:14ms 0.014s 解析Sql字符串:p.ProductCode
IN ( @2dac7a1c4aa64036aeee858b86fbd3a4_0,@2dac7a1c4aa64036aeee858b86fbd3a4_1 )
解析耗时:0ms 0s 解析Sql字符串:p.ProductCode
IN ( @3b6b8fcb2f674cf490d44f97525c3c2b_0,@3b6b8fcb2f674cf490d44f97525c3c2b_1,@3b6b8fcb2f674cf490d44f97525c3c2b_2 )
解析耗时:0ms 0s 解析Sql字符串:p.ProductCode
IN ( @4447c5d65e8a49c9b04549b7aac868b2_0,@4447c5d65e8a49c9b04549b7aac868b2_1,@4447c5d65e8a49c9b04549b7aac868b2_2,@4447c5d65e8a49c9b04549b7aac868b2_3 )
动态表达式
var ex = DynamicWhereExp.Create
var data =await db.Query
db.Aop.DbLog = (sql, dp) =>
{
Console.WriteLine($"执行Sql:{sql}");
if (dp != null)
{
foreach (var item in dp)
{
Console.WriteLine($"参数名称:{item.ParameterName} 参数值:{item.Value}");
}
}
};
普通事务
try
{
await db.Ado.BeginTranAsync();//开启事务
// 执行 CRUD
await db.Ado.CommitTranAsync();//提交事务
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
await db.Ado.RollbackTranAsync();//回滚事务
}
更大范围的事务 使用微软 TransactionScope 对象
using (var tran = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// 执行你的增删改查
// 可使用原生Ado或DbContext对象的CURD方法
tran.Complete();//提交事务
}
改变数据库
//数据库配置可从Json配置文件加载
IDbContext db = new DbContext(new List
new DbOptions()
{
DbId = "0",
DbType = Models.DbType.SQLServer,
ProviderName = "System.Data.SqlClient",
FactoryName = "System.Data.SqlClient.SqlClientFactory,System.Data",
ConnectionStrings = "server=localhost;database=Test;user=sa;pwd=123456789;min pool size=3;max pool size=100;connect timeout=30;"
},
new DbOptions()
{
DbId = "1",
DbType = Models.DbType.MySQL,
ProviderName = "MySqlConnector",
FactoryName = "MySqlConnector.MySqlConnectorFactory,MySqlConnector",
ConnectionStrings = "server=localhost;database=Test;user=root;pwd=123456789;port=3306;min pool size=3;max pool size=100;connect timeout=30;"
}});
db.ChangeDb("1");//切换到MySQL
/// <summary>
/// 产品
/// </summary>
[Table("ProductMain")]
public class Product
{
/// <summary>
/// 产品ID
/// </summary>
[Key]
public int ProductId { get; set; }
/// <summary>
/// 产品编号
/// </summary>
[Column("ProductCode")]//不标记默认取当前属性名称
public string ProductCode { get; set; }
/// <summary>
/// 自定义1
/// </summary>
[NotMapped]
public string Custom1 { get; set; }
}
// 原始起步
// var conn = db.Ado.DbProviderFactory.CreateConnection();
// var cmd = conn.CreateCommand();
// 封装的方法分别以Execute和Create开头以及预处理 PrepareCommand 方法
// 该方法可以自动帮你处理执行的预操作,主要作用是代码复用。
// 当有非常复杂的查询 ORM不能满足需求的时候可以使用原生Ado满足业务需求
// 构建数据集核心扩展方法 分别有 FristBuildAsync ListBuildAsync DictionaryBuildAsync DictionaryListBuildAsync
var data = await db.Ado.ExecuteReaderAsync(CommandType.Text, "select * from product", null).ListBuildAsync<Product>();
手机扫一扫
移动阅读更方便
你可能感兴趣的文章