在 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),然后继续找到下一层方法 就能看到如下代码: 看到这个注 ...
随机推荐
- Java(五、类和对象中的例题)
一.方法中的参数为数值型的(int) import java.util.Scanner; public class ScoreCalc { public void calc(int num1,int ...
- Maven学习(六)-- Maven与Eclipse整合
由于我使用的是IDEA所以就不摘录了,感兴趣的移步 Maven学习总结(六)--Maven与Eclipse整合 Maven学习总结(七)--eclipse中使用Maven创建Web项目
- redux 中间件 --- applyMiddleware 源码解析 + 中间件的实战
前传 中间件的由来 redux的操作的过程,用户操作的时候,我们通过dispatch分发一个action,纯函数reducer检测到该操作,并根据action的type属性,进行相应的运算,返回st ...
- jmeter接口测试报java.net.SocketException: Socket closed错误。
如题,jmeter报出java.net.SocketException: Socket closed,我查询了下,服务器是正常的,可以返回数据,基本确定问题出在我这边jmeter.查询原因,看到有人说 ...
- virsh命令来创建虚拟机
virsh命令来创建虚拟机步骤 (1)生成硬盘镜像文件: 格式:raw或qcow2 # qemu-img create -f raw fdisk.img 10G qemu-img convert re ...
- 并行(Parallelism)与并发(Concurrency)
并行(Parallelism):多任务在同一时刻运行.例如,多个任务在多核处理器上运行. 并发(Concurrency):两个或者两个以上的任务在一段时间内开始.运行.完成,这意味着它们不是在同一时刻 ...
- 十九、Hadoop学记笔记————Hbase和MapReduce
概要: hadoop和hbase导入环境变量: 要运行Hbase中自带的MapReduce程序,需要运行如下指令,可在官网中找到: 如果遇到如下问题,则说明Hadoop的MapReduce没有权限访问 ...
- Linux内核中的算法和数据结构
算法和数据结构纷繁复杂,但是对于Linux Kernel开发人员来说重点了解Linux内核中使用到的算法和数据结构很有必要. 在一个国外问答平台stackexchange.com的Theoretica ...
- 分布式服务跟踪及Spring Cloud的实现
在分布式服务架构中,需要对分布式服务进行治理——在分布式服务协同向用户提供服务时,每个请求都被哪些服务处理?在遇到问题时,在调用哪个服务上发生了问题?在分析性能时,调用各个服务都花了多长时间?哪些调用 ...
- jmeter使用csv进行参数化(二)
上篇说的是csv的第一种方法进行参数化,这篇说第二种方法. 重新打开录制好的脚本. 1.提取函数变量 打开选项--函数助手对话框 设置对话框参数: 选择csvread,然后将变量文件的路径填写进来.添 ...