var repo = fsql.GetRepository();
repo.InsertOrUpdate(实体);
fsql.Select()
.WithSql("select * from Topic where clicks > 10")
.Page(1, 10)
.ToList()
//SELECT a.`Id`, a.`Clicks`, a.`CategoryId`, a.`Title`, a.`CreateTime`
//FROM (select * from Topic where clicks > 10) a
//LIMIT 10
List t2 = fsql.Select.ToTreeList();
List t3 = fsql.Select.Where(a => a.Name = "家电").AsTreeCte().ToTreeList();
//v1.6.0 AsTreeCte() 递归CTE查询 家电 下的所有子分类
ToTreeList 查询数据后加工为树型,注意:实体需要配置父子导航属性
//返回 AsTreeCte() 树状层级信息
t4 = fsql.Select()
.Where(a => a.Name == "中国")
.AsTreeCte(a => a.Name + "[" + a.Code + "]")
.OrderBy(a => a.Code)
.ToList(a => new { item = a, level = Convert.ToInt32("a.cte_level"), path = "a.cte_path" });
Assert.Equal(4, t4.Count);
Assert.Equal("100000", t4[0].item.Code);
Assert.Equal("110000", t4[1].item.Code);
Assert.Equal("110100", t4[2].item.Code);
Assert.Equal("110101", t4[3].item.Code);
Assert.Equal("中国[100000]", t4[0].path);
Assert.Equal("中国[100000] -> 北京[110000]", t4[1].path);
Assert.Equal("中国[100000] -> 北京[110000] -> 北京市[110100]", t4[2].path);
Assert.Equal("中国[100000] -> 北京[110000] -> 东城区[110101]", t4[3].path);
有设置导航属性关系的(支持一对多、多对多):
fsql.Select().IncludeMany(a => a.Goods).ToList();
未设置导航属性关系的,临时指定关系(只支持一对多):
fsql.Select().IncludeMany(a => a.Comment.Where(b => b.TagId == a.Id));
只查询每项子集合的前几条数据,避免像EfCore加载所有数据导致IO性能低下(比如某商品下有2000条评论):
fsql.Select().IncludeMany(a => a.Comment.Take(10));
在 Dto 上做映射 IncludeMany:
//定义临时类,也可以是 Dto 类
class Dto {
public int TypeId { get; set; }
public List GoodsList { get; set; }
}
//查询 Goods 商品表,分类1、分类2、分类3 各10条数据
var dto = new [] { 1,2,3 }.Select(a => new Dto { TypeId = a }).ToList();
dto.IncludeMany(d => d.GoodsList.Take(10).Where(gd => gd.TypeId == d.TypeId));
//执行后,dto 每个元素.Vods 将只有 10条记录
查询子集合表的部分字段,避免子集合字段过多的问题:
fsql.Select().IncludeMany(a => a.Goods.Select(b => new Goods { Id = b.Id, Title = b.Title }));
//只查询 goods 表 id, title 字段,再作填充
多表查询时,像isdeleted每个表都给条件,挺麻烦的。WhereCascade使用后生成sql时,所有表都附上这个条件。
如:
fsql.Select()
.LeftJoin(...)
.WhereCascade(x => x.IsDeleted == false)
.ToList();
方式一:完整保存,对比表已存在的数据,计算出添加、修改、删除执行
var repo = fsql.GetRepository();
repo.Insert(item);
repo.SaveMany(item, "Childs");
方式二:追加保存,不删除表已存在的数据
var repo = fsql.GetRepository();
repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; //需要手工开启
repo.Insert(item);
默认 IDelete 不支持导航对象,多表关联等。ISelect.ToDelete 可将查询转为删除对象,以便支持导航对象或其他查询功能删除数据,如下:
fsql.Select().Where(a => a.Options.xxx == 1).ToDelete().ExecuteAffrows();
注意:此方法不是将数据查询到内存循环删除,上面的代码产生如下 SQL 执行:
DELETE FROM `T1` WHERE id in (select a.id from T1 a left join Options b on b.t1id = a.id where b.xxx = 1)
之前:
FreeSql.DbContext 和 仓储实现,已经实现了联级保存功能,联级保存功能可实现保存对象的时候,将其【OneToMany】、【ManyToMany】导航属性集合也一并保存。
全局关闭:
fsql.SetDbContextOptions(opt => opt.EnableAddOrUpdateNavigateList = false);
局部关闭:
var repo = fsql.GetRepository();
repo.DbContextOptions.EnableAddOrUpdateNavigateList = false;
如果因为某个 sql 骚操作耗时很高,没有一个相关的审计功能,排查起来可以说无从下手。
FreeSql 支持简单的类似功能:
fsql.Aop.CurdAfter += (s, e) => {
if (e.ElapsedMilliseconds > 200) {
//记录日志
//发送短信给负责人
}
};
实现插入/更新时统一处理某些值,比如某属性的雪花算法值、创建时间值、甚至是业务值。
fsql.Aop.AuditValue += (s, e) => {
if (e.Column.CsType == typeof(long)
&& e.Property.GetCustomAttribute(false) != null
&& e.Value?.ToString() == 0)
e.Value = new Snowflake().GetId();
};
class Order {
[Snowflake]
public long Id { get; set; }
//...
}
class EnumTestMap {
public Guid id { get; set; }
[Column(MapType = typeof(string))]
public ToStringMapEnum enum_to_string { get; set; }
[Column(MapType = typeof(string))]
public ToStringMapEnum? enumnullable_to_string { get; set; }
[Column(MapType = typeof(int))]
public ToStringMapEnum enum_to_int { get; set; }
[Column(MapType = typeof(int?))]
public ToStringMapEnum? enumnullable_to_int { get; set; }
[Column(MapType = typeof(string))]
public BigInteger biginteger_to_string { get; set; }
[Column(MapType = typeof(string))]
public BigInteger? bigintegernullable_to_string { get; set; }
}
public enum ToStringMapEnum { 中国人, abc, 香港 }
class Topic {
[Column(ServerTime = DateTimeKind.Utc, CanUpdate = false)]
public DateTime CreateTime { get; set; }
[Column(ServerTime = DateTimeKind.Utc)]
public DateTime UpdateTime { get; set; }
}
值对象映射成 typeof(string),安装扩展包:
dotnet add package FreeSql.Extensions.JsonMap
fsql.UseJsonMap(); //开启功能
class TestConfig {
public int clicks { get; set; }
public string title { get; set; }
}
[Table(Name = "sysconfig")]
public class S_SysConfig {
[Column(IsPrimary = true)]
public string Name { get; set; }
[JsonMap]
public TestConfig Config { get; set; }
}
适用场景:当实体类继承时,CodeFirst创建表的字段顺序可能不是想要的,通过该特性可以设置顺序。
创建表时指定字段位置,如:[Column(Position = 1],可为负数即反方向位置;
IFreeSql.CodeFirst.IsAutoSyncStructure 可设置全局【自动迁移结构】功能,也可通过 FreeSqlBuilder.UseAutoSyncStructure(true) 创建 IFreeSql 的时候设置功能。
当【实体类】对应的是数据库【视图】或者其他时,可通过 [Table(DisableSyncStructure = true)] 禁用指定的实体迁移操作。
[Table(DisableSyncStructure = true)]
class ModelDisableSyncStructure {
[Column(IsPrimary = false)]
public int pkid { get; set; }
}