efcore 实体配置_在 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 功能简单。

解决方法

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 配置实体,参考:外链网址已屏蔽;

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 != Microsoft.EntityFrameworkCore.Metadata.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 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().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().AppendData(new Song()).ToSql());

"INSERT INTO "Songs"("Title") VALUES(@Title0)"

//此处配置已生效,Id 为自增时不插入,表名也改名了 Songs

有几个问题

本人对 EF 不太熟,有几个问题请教:

1、EFCore 是不是非要定义 DBContext 来使用?

2、Microsoft.EntityFrameworkCore.Metadata.IModel 有没有变化通知或拦截的方法?简化配置;

3、EFCore 自增各种数据库的现实貌似有差异?

结束语

感谢观看,以上是我的解决思路,如果有更好的建议或方法欢迎讨论。

FreeSql 虽然目前的版本发布为 0.xx,但功能和可能性已经较高了。

Github:外链网址已屏蔽

Wiki:外链网址已屏蔽

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值