我们知道 EFCore for oracle 问题多,并且现在还没更新到 3.x,在这样的背景下,一个国产数据库更不能指望谁实现好用的 EFCore。目前看来除了 EFCore for sqlserver 我们没把握完全占优势,起码在其他数据库肯定是我们更接地气。
言归正传,达梦数据库其实蛮早就支持了,之前是以 Odbc 的方式实现的,后面根据使用者的反馈 Odbc 环境问题比较麻烦,经研究决定支持 ado.net 适配,让使用者更加方便。使用 ado.net 方式连接达梦只需要修改 IFreeSql 创建时候的类型即可,如下:
static IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnectionString(FreeSql.DataType.Dameng, connectionString) .UseAutoSyncStructure(true) //自动同步实体结构到数据库 .Build(); //请务必定义成 Singleton 单例模式 七、兼容 EFCore 实体特性、FluentApiEFCore 目前用户量最多,为了方便一些项目过渡到 FreeSql,我们做了一些 “AI”:
自动识别 EFCore 实体特性:Key/Required/NotMapped/Table/Column
[Table("table01")] //这个其实是 EFCore 的特性 class MyTable { [Key] public int Id { get; set; } }与 EFCore 90% 相似的 FluentApi
fsql.CodeFirst.Entity<Song>(eb => { eb.ToTable("tb_song"); eb.Ignore(a => a.Field1); eb.Property(a => a.Title).HasColumnType("varchar(50)").IsRequired(); eb.Property(a => a.Url).HasMaxLength(100); eb.Property(a => a.RowVersion).IsRowVersion(); eb.Property(a => a.CreateTime).HasDefaultValueSql("current_timestamp"); eb.HasKey(a => a.Id); eb.HasIndex(a => new { a.Id, a.Title }).IsUnique().HasName("idx_xxx11"); //一对多、多对一 eb.HasOne(a => a.Type).HasForeignKey(a => a.TypeId).WithMany(a => a.Songs); //多对多 eb.HasMany(a => a.Tags).WithMany(a => a.Songs, typeof(Song_tag)); }); fsql.CodeFirst.Entity<SongType>(eb => { eb.HasMany(a => a.Songs).WithOne(a => a.Type).HasForeignKey(a => a.TypeId); eb.HasData(new[] { new SongType { Id = 1, Name = "流行", Songs = new List<Song>(new[] { new Song{ Title = "真的爱你" }, new Song{ Title = "爱你一万年" }, }) }, new SongType { Id = 2, Name = "乡村", Songs = new List<Song>(new[] { new Song{ Title = "乡里乡亲" }, }) }, }); }); public class SongType { public int Id { get; set; } public string Name { get; set; } public List<Song> Songs { get; set; } } public class Song { [Column(IsIdentity = true)] public int Id { get; set; } public string Title { get; set; } public string Url { get; set; } public DateTime CreateTime { get; set; } public int TypeId { get; set; } public SongType Type { get; set; } public int Field1 { get; set; } public long RowVersion { get; set; } } 八、ISelect.ToTreeList 查询树型数据 List这是几个意思?有做过父子关系的表应该知道的,把数据查回来了是平面的,需要再用递归转化为树型。考虑到这个功能实用性比较高,所以就集成了进来。来自单元测试的一段代码:
var repo = fsql.GetRepository<VM_District_Child>(); repo.DbContextOptions.EnableAddOrUpdateNavigateList = true; repo.DbContextOptions.NoneParameter = true; repo.Insert(new VM_District_Child { Code = "100000", Name = "中国", Childs = new List<VM_District_Child>(new[] { new VM_District_Child { Code = "110000", Name = "北京市", Childs = new List<VM_District_Child>(new[] { new VM_District_Child{ Code="110100", Name = "北京市" }, new VM_District_Child{ Code="110101", Name = "东城区" }, }) } }) }); var t3 = fsql.Select<VM_District_Child>().ToTreeList(); Assert.Single(t3); Assert.Equal("100000", t3[0].Code); Assert.Single(t3[0].Childs); Assert.Equal("110000", t3[0].Childs[0].Code); Assert.Equal(2, t3[0].Childs[0].Childs.Count); Assert.Equal("110100", t3[0].Childs[0].Childs[0].Code); Assert.Equal("110101", t3[0].Childs[0].Childs[1].Code);注意:实体需要配置父子导航属性
九、BulkCopy 大批量数据原先 FreeSql 对批量数据操作就做得还可以,例如批量数据超过数据库某些限制的,会拆分执行,性能其实也还行。
本需求也是来自用户,然后就实现了,实现完了我还专门做了性能测试对比,sqlserver bulkcopy 收益比较大,mysql 收益非常小。
测试结果(52个字段,18W-50行数据,单位ms):
18W 1W 5K 500 50MySql 5.5 ExecuteAffrows 38,481 2,234 1,136 167 30
MySql 5.5 ExecuteMySqlBulkCopy 28,405 1,142 657 592 22
SqlServer Express ExecuteAffrows 402,355 24,847 11,465 915 88
SqlServer Express ExecuteSqlBulkCopy 21,065 578 326 79 48
PostgreSQL 10 ExecuteAffrows 46,756 3,294 2,269 209 37
PostgreSQL 10 ExecutePgCopy 10,090 583 337 61 25
Oracle XE ExecuteAffrows - - - 10,648 200
Sqlite ExecuteAffrows 28,554 1,149 701 91 35
Oracle 插入性能不用怀疑,可能安装学生版限制较大