update

28810
2020-02-27 17:25:35 +08:00
parent 3d2a9d354d
commit abd17cec40
6 changed files with 31 additions and 134 deletions

@@ -7,7 +7,7 @@ FreeSql.Repository 作为扩展,实现了通用仓储层功能。与其他规
## 定义
```csharp
var fsql = new FreeSql.FreeSqlBuilder()
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Pooling=true;Max Pool Size=10")
.UseAutoSyncStructure(true) //自动迁移实体的结构到数据库
.Build(); //请务必定义成 Singleton 单例模式
@@ -24,11 +24,10 @@ public class Song {
1、IFreeSql 的扩展方法;
```csharp
var curd1 = fsql.GetRepository<Song, int>();
var curd2 = fsql.GetGuidRepository<Song>();
var curd = fsql.GetRepository<Song>();
```
> 注意:BaseRepository 对象多线程不安全
> 注意:多线程不安全
2、继承实现

@@ -1,5 +1,5 @@
```csharp
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
.Build(); //请务必定义成 Singleton 单例模式

@@ -1,5 +1,5 @@
```csharp
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
.Build(); //请务必定义成 Singleton 单例模式
@@ -28,13 +28,8 @@ class TestTypeParentInfo {
ISelect<Topic> select => fsql.Select<Topic>();
```
## 1、(联表)利用导航属性
## 1、导航属性联表
```csharp
sql = select.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid).ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a
//LEFT JOIN `TestTypeInfo` a__Type ON a__Type.`Guid` = a.`TestTypeInfoGuid`
sql = select
.LeftJoin(a => a.Type.Guid == a.TestTypeInfoGuid)
.LeftJoin(a => a.Type.Parent.Id == a.Type.ParentId).ToSql();
@@ -54,24 +49,22 @@ sql = select.LeftJoin<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid).ToSq
//LEFT JOIN `TestTypeInfo` b ON b.`Guid` = a.`TestTypeInfoGuid`
```
## 3、任意联表
## 3、复杂联表
```csharp
sql = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
.LeftJoin(a => a.TestTypeInfoGuid == b.Guid)
.LeftJoin(a => b.ParentId == c.Id)).ToSql();
//或者
sql = fsql.Select<Topic, TestTypeInfo, TestTypeParentInfo>()
.LeftJoin((a,b,c) => a.TestTypeInfoGuid == b.Guid)
.LeftJoin((a,b,c) => b.ParentId == c.id).ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a
//LEFT JOIN `TestTypeInfo` b ON a.`TestTypeInfoGuid` = b.`Guid`
//LEFT JOIN `TestTypeParentInfo` c ON b.`ParentId` = c.`Id`
```
或者
```csharp
sql = fsql.Select<Topic, TestTypeInfo, TestTypeParentInfo>()
.LeftJoin((a,b,c) => a.TestTypeInfoGuid == b.Guid)
.LeftJoin((a,b,c) => b.ParentId == c.id).ToSql();
```
## 4、SQL联表
```csharp
sql = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname", new { bname = "xxx" }).ToSql();
@@ -80,42 +73,7 @@ sql = select.LeftJoin("TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name
//LEFT JOIN TestTypeInfo b on b.Guid = a.TestTypeInfoGuid and b.Name = ?bname
```
## 5、利用导航属性,查询条件
```csharp
sql = select.Where(a => a.Type.Name == "typeTitle" && a.Type.Guid == a.TestTypeInfoGuid).ToSql();
///SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a__Type.`Guid`, a__Type.`ParentId`, a__Type.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a, `TestTypeInfo` a__Type
//WHERE (a__Type.`Name` = 'typeTitle' AND a__Type.`Guid` = a.`TestTypeInfoGuid`)
```
## 6、没有导航属性查询条件
```csharp
sql = select.Where<TestTypeInfo>((a, b) => b.Guid == a.TestTypeInfoGuid && b.Name == "typeTitle").ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a, `TestTypeInfo` b
//WHERE (b.`Guid` = a.`TestTypeInfoGuid` AND b.`Name` = 'typeTitle')
```
## 7、任意条件
```csharp
sql = select.From<TestTypeInfo, TestTypeParentInfo>((s, b, c) => s
.Where(a => a.Id == 10 && c.Name == "xxx")
.Where(a => b.ParentId == 20)).ToSql();
//SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, b.`Guid`, b.`ParentId`, b.`Name`, a.`Title`, a.`CreateTime`
//FROM `tb_topic` a, `TestTypeParentInfo` c, `TestTypeInfo` b
//WHERE (a.`Id` = 10 AND c.`Name` = 'xxx') AND (b.`ParentId` = 20)
```
或者
```csharp
sql = fsql.Select<Topic, TestTypeInfo, TestTypeParentInfo>()
.Where((a, b, c) => a.Id == 10 && c.Name == "xxxx")
.Where((a, b, c) => b.ParentId == 20)
.ToSql();
```
## 8、子表 Exists
## 5、子表Exists
```csharp
var list2 = select.Where(a => select.As("b").Where(b => b.Id == a.Id).Any()).ToList();
// SELECT a.`Id`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
@@ -127,7 +85,7 @@ var list2 = select.Where(a => select.As("b").Where(b => b.Id == a.Id).Any()).ToL
> 提示:由于子查询的实体类与上层相同,使用 As("b") 指明别名,以便区分
## 9、子表 In
## 6、子表In
```csharp
var list2 = select.Where(a => select.As("b").ToList(b => b.Id).Contains(a.Id)).ToList();
@@ -137,7 +95,7 @@ var list2 = select.Where(a => select.As("b").ToList(b => b.Id).Contains(a.Id)).T
// FROM `tb_topic` b)))
```
## 10、子表 First/Count/Sum/Max/Min/Avg
## 7、子表First/Count/Sum/Max/Min/Avg
```csharp
var subquery = select.ToSql(a => new {
all = a,
@@ -150,7 +108,7 @@ var subquery = select.ToSql(a => new {
});
```
## 11、AsSelect
## 8、AsSelect
```csharp
fsql.Select<TestTypeInfo>()
@@ -168,7 +126,7 @@ fsql.Select<TestTypeInfo>()
将集合属性快速转换为 ISelect 进行子查询操作。
## 12、WhereCascade
## 9、WhereCascade
多表查询时像isdeleted每个表都给条件挺麻烦的。WhereCascade使用后生成sql时所有表都附上这个条件。
@@ -190,7 +148,7 @@ LEFT JOIN t2 on ... AND (t2.IsDeleted = 0)
WHERE t1.IsDeleted = 0
```
其中的实体可附加表达式时才生效,支持子表查询。单次查询使用的表数目越多收益越大。
实体可附加表达式时才生效,支持子表查询。单次查询使用的表数目越多收益越大。
可应用范围:

@@ -8,6 +8,8 @@ fsql.CodeFirst.IsConfigEntityFromDbFirst = true;
此功能目前可用于 mysql/sqlserver/postgresql/oracle。
> 开启该功能会增加首次执行时间(耗时情况和表数量有关)
## 优先级
数据库特性 > 实体特性 > FluentApi配置特性 > Aop配置特性

@@ -18,25 +18,23 @@ var t1 = fsql.Select<T>()
现在where id in (1..500) or id in (501..1000) or id in (1001..1333)
In 只能实现单列查询,多列怎么办?
## In多列查询
```csharp
//元组集合
vae lst = new List<(Guid, DateTime)>();
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
lst.Add((Guid.NewGuid(), DateTime.Now));
var t2 = fsql.Select<T>()
.Where(a => lst.Contains(a.Id, a.ct1))
.ToSql();
//SELECT .. FROM ..
//WHERE (a."Id" = '685ee1f6-bdf6-4719-a291-c709b8a1378f' AND a."ct1" = '2019-12-07 23:55:27' OR
//a."Id" = '5ecd838a-06a0-4c81-be43-1e77633b7404' AND a."ct1" = '2019-12-07 23:55:27' OR
//a."Id" = 'b8b366f3-1c03-4547-9c96-d362dd5cae6a' AND a."ct1" = '2019-12-07 23:55:27')
//a."Id" = '5ecd838a-06a0-4c81-be43-1e77633b7404' AND a."ct1" = '2019-12-07 23:55:27')
```
## 子表 In
## In子表
```csharp
var list2 = select.Where(a => select.ToList(b => b.Id).Contains(a.Id)).ToList();
@@ -46,7 +44,7 @@ var list2 = select.Where(a => select.ToList(b => b.Id).Contains(a.Id)).ToList();
// FROM `tb_topic` b)))
```
## 子表 Exists
## Exists子表
```csharp
var list2 = select.Where(a => select.Where(b => b.Id == a.Id).Any()).ToList();
// SELECT a.`Id`, a.`TypeGuid`, a.`Title`, a.`CreateTime`
@@ -63,11 +61,12 @@ var t3 = fsql.Select<T>().Where(a => a.CreateTime.Date == DateTime.Today).ToSql(
//这行代码说明 FreeSql 表达式解析强大,不是所有 ORM 都支持
var t4 = fsql.Select<T>().Where(a => a.CreateTime.Between(DateTime.Today, DateTime.Today.AddDays(1))).ToSql();
//正常用法应该是这样
```
> SqlServer nvarchar/varchar 已兼容表达式解析分别解析为N'' 和 '',优化索引执行计划;
## 自定义表达式函数(v0.11.23)
## 自定义解析
```csharp
[ExpressionCall]
@@ -83,39 +82,12 @@ public static class DbFunc
context.Value.Result = $"date_format({up.ParsedContent["that"]}, {up.ParsedContent["arg1"]})";
return that;
}
public static string SetDbParameter(this string that, int size)
{
if (context.Value.DbParameter != null)
{
//已经参数化了,直接修改长度
//提示:此条件可能开启了全局表达式参数化功能 UseGenerateCommandParameterWithLambda(true)
context.Value.DbParameter.Size = size;
return that;
}
var guid = Guid.NewGuid().ToString("N").ToLower();
context.Value.UserParameters.Add(new SqlParameter
{
ParameterName = guid,
SqlDbType = System.Data.SqlDbType.VarChar,
Size = size,
Value = that
});
return $"@{guid}"; //重写内容
}
}
var sql1 = fsql.Select<SysModule>()
.ToSql(a => a.CreateTime.FormatDateTime("yyyy-MM-dd"));
//SELECT date_format(a."CreateTime", 'yyyy-MM-dd') as1
//FROM "SysModule" a
var sql2 = fsql.Select<SysModule>()
.Where(a => a.Title == "123123".SetDbParameter(20))
.ToSql();
//SELECT ...
//FROM [SysModule] a
//WHERE (a.[Title] = @6a8b79d7001540369a2f52ecbba15679)
```
\[ExpressionCall\] 特性可在静态扩展类上标记,也可以在单个静态方法上标记;
@@ -130,7 +102,7 @@ var sql2 = fsql.Select<SysModule>()
> 当扩展方法返回值为 string 时,其返回值也可以当作 context.Value.Result 功能
## 命令参数化(v0.12.1)
## 参数化
在之前 Where(lambda) 解析出来的是纯文本,做了防止注入功能,对数据库执行计划要求高的,现在可以开启 lambda 参数化功能。
@@ -184,40 +156,6 @@ public static class DbFunc
![image](https://user-images.githubusercontent.com/16286519/69433211-2c5fcf80-0d76-11ea-8eec-963eb37199c5.png)
## AOP拦截解析
IFreeSql 对象有 Aop 成员,那里提供一堆 AOP 拦截的方法。其实有一个事件名称ParseExpression。
```csharp
/// <summary>
/// 可自定义解析表达式
/// </summary>
EventHandler<AopParseExpressionEventArgs> ParseExpression { get; set; }
public class AopParseExpressionEventArgs : EventArgs {
public AopParseExpressionEventArgs(Expression expression, Func<Expression, string> freeParse) {
this.Expression = expression;
this.FreeParse = freeParse;
}
/// <summary>
/// 内置解析功能,可辅助您进行解析
/// </summary>
public Func<Expression, string> FreeParse { get; }
/// <summary>
/// 需要您解析的表达式
/// </summary>
public Expression Expression { get; }
/// <summary>
/// 解析后的内容
/// </summary>
public string Result { get; set; }
}
```
FreeParse 是提供给外部的解析工具,它拥有 FreeSql 所有表达式功能,当您自定义解析的过程中遇到特别难处理的,可通过它快速解析出表达式的子部分内容。
## 表达式函数全览
| 表达式 | MySql | SqlServer | PostgreSQL | Oracle | 功能说明 |

@@ -4,7 +4,7 @@ FreeSql 支持数据库读写分离,本功能是客户端的读写分离行为
1、nginx代理配置繁琐且容易出错
2、中件间如MyCatMySql可以其他数据库怎么办
2、中件间如MyCat
3、在client端支持
@@ -18,7 +18,7 @@ FreeSql 实现了第3种方案支持一个【主库】多个【从库】
var connstr = "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;" +
"Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10";
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
static IFreeSql fsql = new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.MySql, connstr)
.UseSlave("connectionString1", "connectionString2") //使用从数据库,支持多个
.Build(); //请务必定义成 Singleton 单例模式