Skip to content

Commit

Permalink
Merge branch 'main' of github.com:2881099/FreeSql.Wiki.VuePress
Browse files Browse the repository at this point in the history
  • Loading branch information
luoyunchong committed Nov 17, 2024
2 parents 59177d8 + 8687de1 commit bc10037
Show file tree
Hide file tree
Showing 11 changed files with 201 additions and 14 deletions.
23 changes: 23 additions & 0 deletions docs/en/guide/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,29 @@ repo.Update(item); // Compare changes from snapshot
Dictionary<string, object[]> CompareState(TEntity newdata);
```

It should be noted that when using Repository updates, `ServerTime` should not be specified in ColumnAttribute.

~~~csharp
var repo = fsql.GetRepository<Dictionaries>();
var item = await repo.Where(a => a.DictId == "1").FirstAsync();

//If the ServerTime property exists in the Column attribute, it may result in the inability to modify it
item.UpdateTime = DateTime.Now;
await repo.UpdateAsync(item);

public class Dictionaries
{
[Column(Name = "id", IsPrimary = true)]
public string Id { get; set; }

[Column(Name = "name")]
public string Name { get; set; }

[Column(Name = "update_time", ServerTime = DateTimeKind.Local)]
public DateTime? UpdateTime { get; set; }
}
~~~

## Login Information (Dependency Injection)

`repo.DbContextOptions.AuditValue` is suitable for integration with AddScoped (Dependency Injection) to uniformly set login information.
Expand Down
8 changes: 4 additions & 4 deletions docs/guide/entity-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,19 +234,19 @@ class JsonPocoTypeHandler : TypeHandler<JsonPoco>
{
public override object Serialize(JsonPoco value) => JsonConvert.SerializeObject(value);
public override JsonPoco Deserialize(object value) => JsonConvert.DeserializeObject<JsonPoco>((string)value);
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).StringLength(-1);
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).StringLength(-1);
}
class DateOnlyTypeHandler : TypeHandler<DateOnly>
{
public override object Serialize(DateOnly value) => value.ToString("yyyy-MM-dd");
public override DateOnly Deserialize(object value) => DateOnly.TryParse(string.Concat(value), out var trydo) ? trydo : DateOnly.MinValue;
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).StringLength(12);
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).StringLength(12);
}
class DateTimeOffsetTypeHandler : TypeHandler<DateTimeOffset>
{
public override object Serialize(DateTimeOffset value) => value.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss");
public override DateTimeOffset Deserialize(object value) => DateTimeOffset.TryParse((string)value, out var dts) ? dts : DateTimeOffset.MinValue;
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).DbType("datetime");
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).DbType("datetime");
}
```

Expand Down Expand Up @@ -278,7 +278,7 @@ fsql.Select<Table>().Where(a => a.Options.Value1 == 100 && a.Options.Value2 == "

适用场景:当实体类继承时,CodeFirst 创建表的字段顺序可能不是想要的,通过该特性可以设置顺序。

创建表时指定字段位置,如:[Column(Position = 1],可为负数即反方向位置;
创建表时指定字段位置,如:[Column(Position = 1)],可为负数即反方向位置;

## 可插入(CanInsert)、可更新(CanUpdate)

Expand Down
80 changes: 78 additions & 2 deletions docs/guide/freeredis.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@
- 🎣 支持主从分离(Master-Slave)
- 📡 支持发布订阅(Pub-Sub)
- 📃 支持 Redis Lua 脚本
- 💻 支持管道(Pipeline)
- 📰 支持事务
- 💻 支持管道(Pipeline)、支持事务、延迟队列、RediSearch
- 🌴 支持 GEO 命令(服务端要求 3.2 及以上版本)
- 🌲 支持 STREAM 类型命令(服务端要求 5.0 及以上版本)
- ⚡ 支持本地缓存(Client-side-cahing,服务端要求 6.0 及以上版本)
Expand Down Expand Up @@ -177,3 +176,80 @@ foreach (var keys in cli.Scan("*", 10, null))
Console.WriteLine(string.Join(", ", keys));
}
```

## 🍡DelayQueue (延时队列)

```c#
var delayQueue = cli.DelayQueue("TestDelayQueue");

//添加队列
delayQueue.Enqueue($"Execute in 5 seconds.", TimeSpan.FromSeconds(5));
delayQueue.Enqueue($"Execute in 10 seconds.", DateTime.Now.AddSeconds(10));
delayQueue.Enqueue($"Execute in 15 seconds.", DateTime.Now.AddSeconds(15));
delayQueue.Enqueue($"Execute in 20 seconds.", TimeSpan.FromSeconds(20));
delayQueue.Enqueue($"Execute in 25 seconds.", DateTime.Now.AddSeconds(25));
delayQueue.Enqueue($"Execute in 2024-07-02 14:30:15", DateTime.Parse("2024-07-02 14:30:15"));

//消费延时队列
await delayQueue.DequeueAsync(s =>
{
output.WriteLine($"{DateTime.Now}:{s}");

return Task.CompletedTask;
});
```

## 🐆 RediSearch

```csharp
cli.FtCreate(...).Execute();
cli.FtSearch(...).Execute();
cli.FtAggregate(...).Execute();
//... or ...
[FtDocument("index_post", Prefix = "blog:post:")]
class TestDoc
{
[FtKey]
public int Id { get; set; }

[FtTextField("title", Weight = 5.0)]
public string Title { get; set; }

[FtTextField("category")]
public string Category { get; set; }

[FtTextField("content", Weight = 1.0, NoIndex = true)]
public string Content { get; set; }

[FtTagField("tags")]
public string Tags { get; set; }

[FtNumericField("views")]
public int Views { get; set; }
}

var repo = cli.FtDocumentRepository<TestDoc>();
repo.CreateIndex();

repo.Save(new TestDoc { Id = 1, Title = "test title1 word", Category = "class 1", Content = "test content 1 suffix", Tags = "user1,user2", Views = 101 });
repo.Save(new TestDoc { Id = 2, Title = "prefix test title2", Category = "class 2", Content = "test infix content 2", Tags = "user2,user3", Views = 201 });
repo.Save(new TestDoc { Id = 3, Title = "test title3 word", Category = "class 1", Content = "test word content 3", Tags = "user2,user5", Views = 301 });

repo.Delete(1, 2, 3);

repo.Save(new[]
{
new TestDoc { Id = 1, Title = "test title1 word", Category = "class 1", Content = "test content 1 suffix", Tags = "user1,user2", Views = 101 },
new TestDoc { Id = 2, Title = "prefix test title2", Category = "class 2", Content = "test infix content 2", Tags = "user2,user3", Views = 201 },
new TestDoc { Id = 3, Title = "test title3 word", Category = "class 1", Content = "test word content 3", Tags = "user2,user5", Views = 301 }
});

var list = repo.Search("*").InFields(a => new { a.Title }).ToList();
list = repo.Search("*").Return(a => new { a.Title, a.Tags }).ToList();
list = repo.Search("*").Return(a => new { tit1 = a.Title, tgs1 = a.Tags, a.Title, a.Tags }).ToList();

list = repo.Search(a => a.Title == "word").Filter(a => a.Views, 1, 1000).ToList();
list = repo.Search("word").ToList();
list = repo.Search("@title:word").ToList();
```
1 change: 1 addition & 0 deletions docs/guide/freescheduler.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ FreeScheduler 是利用 IdleBus 实现的轻量化定时任务调度,支持集
```csharp
static Scheduler scheduler = new FreeSchedulerBuilder()
.UseTimeZone(TimeSpan.FromHours(8)) //默认为UTC时间,国内可指定时区+8,任务将按本地时间执行
.OnExecuting(task =>
{
Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");
Expand Down
23 changes: 23 additions & 0 deletions docs/guide/repository.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,29 @@ repo.CompareState(item) 可获取 item 的状态变化信息
Dictionary<string, object[]> CompareState(TEntity newdata);
```

需要注意在使用Repository更新时,不应在ColumnAttribute中指定ServerTime

~~~csharp
var repo = fsql.GetRepository<Dictionaries>();
var item = await repo.Where(a => a.DictId == "1").FirstAsync();

//如果Column特性中存在ServerTime属性可能导致无法修改的情况
item.UpdateTime = DateTime.Now;
await repo.UpdateAsync(item);

public class Dictionaries
{
[Column(Name = "id", IsPrimary = true)]
public string Id { get; set; }

[Column(Name = "name")]
public string Name { get; set; }

[Column(Name = "update_time", ServerTime = DateTimeKind.Local)]
public DateTime? UpdateTime { get; set; }
}
~~~

## 登陆信息(依赖注入)

repo.DbContextOptions.AuditValue 适合与 AddScoped(依赖注入) 信息结合,统一设置登陆信息。
Expand Down
4 changes: 3 additions & 1 deletion docs/guide/sharding.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## 理论知识

分表 - 从表面意思上看呢,就是把一张表分成 N 多个小表,每一个小表都是完整的一张表。分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分表后单表的并发能力提高了,磁盘 I/O 性能也提高了。并发能力为什么提高了呢,因为查寻一次所花的时间变短了,如果出现高并发的话,总表可以根据不同 的查询,将并发压力分到不同的小表里面。
分表 - 从表面意思上看呢,就是把一张表分成 N 多个小表,每一个小表都是完整的一张表。分表后数据都是存放在分表里,总表只是一个外壳,存取数据发生在一个一个的分表里面。分表后单表的并发能力提高了,磁盘 I/O 性能也提高了。并发能力为什么提高了呢,因为查询一次所花的时间变短了,如果出现高并发的话,总表可以根据不同 的查询,将并发压力分到不同的小表里面。

分库 - 把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上。数据库中的数据量不一定是可控的,在未进行分表分库的情况下,随着时间和业务的发展,库中的表会越来越多,表中的数据量也会越来越大,相应地,数据操作,增删改查的开销也会越来越大;另外,一台服务器的资源(CPU、磁盘、内存、IO 等)是有限的,最终数据库所能承载的数据量、数据处理能力都将遭遇瓶颈。

Expand Down Expand Up @@ -202,9 +202,11 @@ fsql.Delete<T>();

```csharp
fsql.Change(DbEnum.db2).Select<T>();
//仅支持 net461+、netcore
//同一线程,或异步await 后续 fsql.Select/Insert/Update/Delete 操作是 db2
fsql.Use(DbEnum.db2).Select<T>();
//支持 net40
//单次有效
using (fsql.Change(DbEnum.db2)) {
Expand Down
20 changes: 18 additions & 2 deletions docs/guide/transaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,21 @@ public class SongService
{
readonly IBaseRepository<Song> _songRepository;
readonly IBaseRepository<Detail> _detailRepository;
readonly UnitOfWorkManager _unitOfWorkManager;

public SongService(IBaseRepository<Song> songRepository, IBaseRepository<Detail> detailRepository)
public SongService(
IBaseRepository<Song> songRepository,
IBaseRepository<Detail> detailRepository,
UnitOfWorkManager unitOfWorkManager
)
{
_songRepository = songRepository;
_detailRepository = detailRepository;
_unitOfWorkManager = unitOfWorkManager;
}

[Transactional]
async public Task Test1()
public async Task Test1()
{
//所有注入的仓储对象,都是一个事务
await _songRepository.InsertAsync(xxx1);
Expand All @@ -97,6 +103,16 @@ public class SongService
public void Test2() //嵌套事务
{
}

public async Task Test3()
{
using (var uow = _unitOfWorkManager.Begin())
{
await _songRepository.InsertAsync(xxx1);
await _detailRepository.DeleteAsync(xxx2);
uow.Commit();
}
}
}
```

Expand Down
6 changes: 3 additions & 3 deletions docs/guide/type-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,19 +108,19 @@ class JsonPocoTypeHandler : TypeHandler<JsonPoco>
{
public override object Serialize(JsonPoco value) => JsonConvert.SerializeObject(value);
public override JsonPoco Deserialize(object value) => JsonConvert.DeserializeObject<JsonPoco>((string)value);
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).StringLength(-1);
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).StringLength(-1);
}
class DateOnlyTypeHandler : TypeHandler<DateOnly>
{
public override object Serialize(DateOnly value) => value.ToString("yyyy-MM-dd");
public override DateOnly Deserialize(object value) => DateOnly.TryParse(string.Concat(value), out var trydo) ? trydo : DateOnly.MinValue;
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).StringLength(12);
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).StringLength(12);
}
class DateTimeOffsetTypeHandler : TypeHandler<DateTimeOffset>
{
public override object Serialize(DateTimeOffset value) => value.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss");
public override DateTimeOffset Deserialize(object value) => DateTimeOffset.TryParse((string)value, out var dts) ? dts : DateTimeOffset.MinValue;
public override void FluentApi(FluentColumn col) => col.MapType(typeof(string)).DbType("datetime");
public override void FluentApi(ColumnFluent col) => col.MapType(typeof(string)).DbType("datetime");
}
```

Expand Down
2 changes: 1 addition & 1 deletion docs/guide/withsql.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ FROM ( select * from TestClass ) a
WHERE ...
```

### 4.返回`List<Tuplue>``List<(string,string)>` 元组
### 4.返回`List<Tuple>``List<(string,string)>` 元组

```csharp
List<(string,string)> list1 = _fsql
Expand Down
36 changes: 36 additions & 0 deletions docs/guide/withtempquery.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,42 @@ INNER JOIN [Unit] c ON a.[UnitId] = c.[UnitId]
WHERE (b.[RN] < 2)
```

## 场景7:报表(每日)

1. 从内存创建连续的日期 List
2. 使用 FromQuery 与多个 ISelect 横向 LeftJoin

```csharp
var startDate = DateTime.Parse("2024-11-1");
var endDate = DateTime.Parse("2024-12-1");
fsql.Select<object>()
.WithMemory(
Enumerable.Range(0, (int)endDate.Subtract(startDate).TotalDays)
.Select(a => new { Date = startDate.AddDays(a).ToString("yyyy-MM-dd") })
.ToList()
)
.FromQuery(
fsql.Select<T1, T2>().InnerJoin((a,b) => ...)
.Where((a,b) => a.CreateDate.BetweenEnd(startDate, endDate)
.GroupBy((a,b) => a.CreateDate.Date.ToString("yyyy-MM-dd"))
.WithTempQuery(g => new { Date = g.Key, Type1Total = g.Sum(g.Value.Item2.Qty1) }),
fsql.Select<T3>()
.Where(a => a.CreateDate.BetweenEnd(startDate, endDate)
.GroupBy(a => a.CreateDate.Date.ToString("yyyy-MM-dd"))
.WithTempQuery(g => new { Date = g.Key, Type2Total = g.Sum(g.Value.Qty2) }),
//... 最多支持 16 个 ISelect 合并
)
.LeftJoin(t => t.t2.Date = t.t1.Date)
.LeftJoin(t => t.t3.Date = t.t1.Date)
.OrderByDescending(t => t.t1.Date)
.ToList(t => new
{
t.t1.Date,
Sum1 = t.t2.Type1Total,
Sum2 t.t3.Type2Total
});
```

## WithParameters 参数化共享

开启参数化查询功能后,使用 WithParameters 共享参数化,可避免产生相同的参数名称:
Expand Down
12 changes: 11 additions & 1 deletion docs/reference/awesome-freesql.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,17 @@
]'
/>


<VPBanner
title="NetAdmin"
content="通用后台权限管理系统、快速开发框架(基于C#12/.NET9、Vue3/Vite、Element Plus等现代技术构建,具有十分整洁、优雅的编码规范)"
:actions='[
{
text: "仓库",
link:"https://github.com/nsnail/NetAdmin",
type: "primary",
},
]'
/>
</div>

<style>
Expand Down

0 comments on commit bc10037

Please sign in to comment.