在 EFCore 定义的实体中进行 FreeSql 开发
EFCore 和 FreeSql 都是 ORM,在各自领域都有着独特的优势。
问题起源
假设某项目是使用 EFCore 开发的,且实体 特性或FluentApi 都配置好了,如:
protected override void MapTable( EntityTypeBuilder builder ) {
    builder.ToTable( "cg_kssqbs" ); //实体表名有单独定义
}
此时用 FreeSql 操作实体会报错:数据库表不存在。除非又配置一套FreeSql的 特性或FluentApi,这显然会比较麻烦。
问:为什么不统一,非要各自定义标准?
答:每个 ORM 的理念不同,提供的功能也不尽相同,FreeSql 的理念是“打造 .NETCore 最方便的 ORM”。与 EFCore 相比只提供了极少的特性配置(如:主键、自增、类型、别名、可空),并且这些设定针对已现实的数据库都是一致的。因此 FreeSql 有单独一套简单的实体配置语法,特别声明:方便、简单指的是上手简单,并非说 FreeSql 功能简单。
来自 Issues 4 《建议能结合EF Core的一些特性来弄 #4》
解决方法
1、关闭 FreeSql 迁移功能
IFreeSql fsql = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
    //.UseAutoSyncStructure(true) //自动同步实体结构到数据库,这行一定要关闭
    .Build();
原因是 EFCore 与 FreeSql 迁移会发生冲突,那边迁移好了,这边又迁移的逻辑显然不对。
2、读取 EFCore 的实体配置数据
Microsoft.EntityFrameworkCore.Metadata.IModel 可以获取 EFCore 的实体配置数据;
FreeSql 已实现了 特性 + FluentApi 配置实体,参考:https://github.com/2881099/FreeSql/wiki/CodeFirst;
ICodeFirst.ConfigEntity 方法可以在程序运行中配置,从而改变实体的映射
以扩展类库的方式现实需求代码如下:
public static void ConfigEntity(this ICodeFirst codeFirst, IModel efmodel) {
    foreach (var type in efmodel.GetEntityTypes()) {
        codeFirst.ConfigEntity(type.ClrType, a => {
            //表名
            var relationalTableName = type.FindAnnotation("Relational:TableName");
            if (relationalTableName != null)
                a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
            foreach (var prop in type.GetProperties()) {
                var freeProp = a.Property(prop.Name);
                //列名
                var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
                if (relationalColumnName != null)
                    freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
                //主键
                freeProp.IsPrimary(prop.IsPrimaryKey());
                //自增
                freeProp.IsIdentity(
                    prop.ValueGenerated == ValueGenerated.Never ||
                    prop.ValueGenerated == ValueGenerated.OnAdd ||
                    prop.GetAnnotations().Where(z =>
                        z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
                        || z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
                    ).Any()
                );
                //可空
                freeProp.IsNullable(prop.AfterSaveBehavior != PropertySaveBehavior.Throw);
                //类型
                var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
                if (relationalColumnType != null) {
                    var dbType = relationalColumnType.ToString();
                    if (!string.IsNullOrEmpty(dbType)) {
                        var maxLength = prop.FindAnnotation("MaxLength");
                        if (maxLength != null)
                            dbType += $"({maxLength})";
                        freeProp.DbType(dbType);
                    }
                }
            }
        });
    }
}
测试
public class Song {
    [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Title { get; set; }
}
public class SongContext : DbContext {
    public DbSet<Song> Songs { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
        optionsBuilder.UseSqlite(@"Data Source=|DataDirectory|\document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10");
    }
}
Console.WriteLine(fsql.Insert<Song>().AppendData(new Song()).ToSql());
//INSERT INTO "Song"("Id", "Title") VALUES(@Id0, @Title0)
using (var sdb = new SongContext()) {
    Fsql.CodeFirst.ConfigEntity(sdb.Model);
    //ps: 只需要配置一次
}
Console.WriteLine(fsql.Insert<Song>().AppendData(new Song()).ToSql());
"INSERT INTO "Songs"("Title") VALUES(@Title0)"
//此处配置已生效,Id 为自增时不插入,表名也改名了 Songs
示范项目已整理上传到 Github/Examples/efcore_to_freesql
有几个问题
本人对 EF 不太熟,有几个问题请教:
1、EFCore 是不是非要定义 DBContext 来使用?
2、Microsoft.EntityFrameworkCore.Metadata.IModel 有没有变化通知或拦截的方法?简化配置;
3、EFCore 自增各种数据库的现实貌似有差异?
结束语
感谢观看,以上是我的解决思路,如果有更好的建议或方法欢迎讨论。
FreeSql 虽然目前的版本发布为 0.xx,但功能和可能性已经较高了。
Github:https://github.com/2881099/FreeSql
Wiki:https://github.com/2881099/FreeSql/wiki
在 EFCore 定义的实体中进行 FreeSql 开发的更多相关文章
- 【mybatis】mybatis使用java实体中定义的常量,或静态方法
		
mybatis使用java实体中定义的常量 示例代码: <select id="findDealerInfo" parameterType="com.pisen.c ...
 - Java定义bean实体类中的变量时变量名的问题
		
首先:TMD,这个问题花了我两个多小时,居然是因为一个字母的大小写导致的,我瞬间就&Y^%^&%&()*%¥%¥¥&^#@%&; 事情是酱紫的: 我定义了一个变 ...
 - Nutz Dao实体中索引注解的使用(@TableIndexes@Index)
		
Nutz是一组轻便小型的框架的集合, 各个部分可以被独立使用,把SSH的精华封装在一个1M左右的jar包中,Nutz不对其他任何第三方库产生依赖,如果不考虑数据库链接和日志的话,创建完美的Web应用只 ...
 - JavaBean定义、JSP中使用以及内省操作
		
Apache commons 一系列的开源工具室非常值得学习的实现. 一 JavaBean定义 JavaBean是一种可重复使用.且跨平台的软件组件.JavaBean可分为两种:一种是 ...
 - Drupal 自己定义主题实体 Theming Custom Entities
		
在自己定义主题中输出结果时,有三个部分或很多其它特殊的函数.如 hook_menu,Page Callback.MODULE_theme 钩子 1.hook_menu 为了使用自己定义的实体.像创建. ...
 - EFCore:关于DDD中值对象(Owns)无法更新数值
		
最近使用DDD+EFCore时,使用EFCore提供的OwnsOne或者OwnsMany关联值对象保存数据,没想到遇到一个很奇怪的问题:值对象中的值竟然无法被EFCore保存!也没有抛出任何异常!我瞬 ...
 - MongoDB学习笔记~MongoDB实体中的值对象
		
回到目录 注意,这里说的值对象是指在MongoDB实体类中的,并不是DDD中的值对象,不过,两者也是联系,就是它是对类的补充,自己本身没有存在的价值,而在值对象中,也是不需要有主键Id的,这与DDD也 ...
 - entity.Student@150f3932, entity.Student@1a740c6b   没有实体中的数据
		
public class AppServerAction extends BaseAction { /** * */ /** * 初始化 “我的产品”列表 JSP页面 ...
 - petapoco 实体中字段去掉关联(类似于EF中的NotMap)
		
怎么才能让不是数据库表中的字段放在实体中而不影响正常的插入和更新呢? 找到 PetaPoco.cs 文件,打开之后,搜索插入方法(Insert),然后继续找到下一层方法 就能看到如下代码: 看到这个注 ...
 
随机推荐
- asp.net core ABP模板本地化设置
			
ABP的语言本地化设置非常方便,甚至地区图标ABP框架都已经有了. 先看看结果吧. 英文的界面 中文的界面 配置流程如下: 首先在Localization目录下新建一个对应的json文件,里面存放对应 ...
 - lintcode 在O(1)时间复杂度删除链表节点
			
题目要求 给定一个单链表中的一个等待被删除的节点(非表头或表尾).请在在O(1)时间复杂度删除该链表节点. 样例 Linked list is 1->2->3->4, and giv ...
 - Flask快速入门
			
flask快速入门 1.1.三种框架比较 Django: 重武器,内部包含了非常多组件:ORM.Form.ModelForm.缓存.Session.中间件.信号等 Flask:短小精悍,内部没有太多组 ...
 - cw2vec理论及其实现
			
导读 本文对AAAI 2018(Association for the Advancement of Artificial Intelligence 2018)高分录用的一篇中文词向量论文(cw2ve ...
 - 【转】mysql索引使用技巧及注意事项
			
一.索引的作用 一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重. 在数据 ...
 - TCP的作用
			
1. 首先,TCP提供客户与服务器之间的连接.TCP客户先与某个给定服务器建立一个连接,然后通过该连接与服务器交换数据,最后终止该连接. 2. 其次,TCP提供了可靠性.超时重传.当TCP向另一端发送 ...
 - SSM-MyBatis-02:Mybatis最基础的增删改查(查全部和查单独一个)
			
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 继续上次的开始,这次记录的是增删改查,上次重复过的代码不做过多解释 首先先创建mysql的表和实体类Book ...
 - 基于opencv3.0下的运动车辆识别
			
在opencv的初等应用上,对运动物体的识别主要有帧差或背景差两种方式. 帧差法主要的原理是当前帧与前一帧作差取绝对值: 背景差主要的原理是当前帧与背景帧作差取绝对值: 在识别运动车辆上主要需要以下9 ...
 - 2017年Kali Linux更新源
			
终端输入: leafpad /etc/apt/sources.list 打开更新源配置文件,将下面的更新源复制到原内容的前面: #163网易 Kali源 deb http://mirrors.163. ...
 - client,server,nginx 在使用keepAlive  专题
			
2. TCP keepalive overview In order to understand what TCP keepalive (which we will just call keepali ...