更新: 2019-06-12

不小心踩坑

var adidas = new Supplier { name = "adidas" };
Db.Suppliers.Add(adidas);
Db.SaveChanges(); // 关键
Db.Products.Add(new Product
{supplier = adidas,code = "001",    // supplierId = adidas.Id
});
Db.SaveChanges();

这样会报错哦.

因为第一个 savechange 已经把 adidas 有了 id 那么 product.add 时我又传入了 adidas

那么 ef 会以为我要去创建, 但是它有 id 了啊, sql 就会报错了 (这里 id 是 auto increment 的情况)

所以按上面的写法其实第一个 save change 是多余的, 如果第一个 save change 是必须的话,下面就应该 update foreign key 就好了。

更新 : 2019-05-04

动态生成 fluent api

enum to string 这个方式我们可以通过 fluent api 来实现, 比如下面这样.

modelBuilder.Entity<Order>().Property(p => p.status).IsRequired().HasMaxLength(128).HasConversion(v => v.ToString(),v => (OrderStatus)Enum.Parse(typeof(OrderStatus), v));

但是如果我们有非常多的 table 和 enum,每一个属性都写这么一行...累丫

那么我们可以通过反射来实现这个调用.

步骤如下,首先找出所有的 EntityType

foreach (var entity in modelBuilder.Model.GetEntityTypes())

接着把所有 enum property 找出来

var props = entity.ClrType.GetProperties().Where(p => p.PropertyType.IsEnum).ToList();

然后每一个 prop 都要绑定 HasConversion

foreach (var prop in props)

接着就是反射调用

// modelBuilder.Entity<Order>()
var entityMethod = modelBuilder.GetType().GetMethod(nameof(ModelBuilder.Entity), 1, new Type[] { });
entityMethod = entityMethod.MakeGenericMethod(new[] { entity.ClrType });
var entityTypeBuilder = entityMethod.Invoke(modelBuilder, new object[] { });

接着

// ...Property(entity => entity.status)
var paramType = typeof(Expression<>).MakeGenericType(new[] { typeof(Func<,>).MakeGenericType(new[] { entity.ClrType, prop.PropertyType }) });
var propertyMethod = entityTypeBuilder.GetType().GetMethods().Where(m => m.Name == nameof(EntityTypeBuilder.Property) && m.GetGenericArguments().Count() == 1).Select(m => m.MakeGenericMethod(prop.PropertyType)).Single(m =>{var parameters = m.GetParameters();if (parameters.Count() != 1) return false;return parameters[0].ParameterType == paramType;});
var paramEntityExp = Expression.Parameter(entity.ClrType, "entity");
var getPropExp = Expression.Property(paramEntityExp, prop);
var lambdaExp = Expression.Lambda(getPropExp, paramEntityExp);
var propertyBuilder = propertyMethod.Invoke(entityTypeBuilder, new[] { lambdaExp });

最后

// ...HasConversion(propertyValue => propertyValue.ToString(), sqlValue => (OrderStatus)Enum.Parse(typeof(OrderStatus), propertyValue));
var firstParamPropertyExp = Expression.Parameter(prop.PropertyType, "propertyValue");
var firstParamCallMethod = typeof(Enum).GetMethod(nameof(Enum.ToString), new Type[] { });
var firstParamCallMethodExp = Expression.Call(firstParamPropertyExp, firstParamCallMethod
);
var firstLambdaExp = Expression.Lambda(firstParamCallMethodExp, firstParamPropertyExp);var secondParamPropertyExp = Expression.Parameter(typeof(string), "sqlValue");
var secondParamCallMethod = typeof(Enum).GetMethod(nameof(Enum.Parse), new[] { typeof(Type), typeof(string) });
var secondParamCallMethodExp = Expression.Call(secondParamCallMethod, new Expression[] { Expression.Constant(prop.PropertyType), secondParamPropertyExp });
var secondParamConvertExp = Expression.Convert(secondParamCallMethodExp,prop.PropertyType
);
var secondLambdaExp = Expression.Lambda(secondParamConvertExp, secondParamPropertyExp);var firstParamType = typeof(Expression<>).MakeGenericType(new[] { typeof(Func<,>).MakeGenericType(new[] { prop.PropertyType, typeof(string) }) });
var secondParamType = typeof(Expression<>).MakeGenericType(new[] { typeof(Func<,>).MakeGenericType(new[] { typeof(string), prop.PropertyType }) });
var hasConversionMethod = propertyBuilder.GetType().GetMethods().Where(m => m.Name == nameof(PropertyBuilder.HasConversion) && m.GetGenericArguments().Count() == 1).Select(m => m.MakeGenericMethod(typeof(string))).Single(m =>{var parameters = m.GetParameters();if (parameters.Count() != 2) return false;return parameters[0].ParameterType == firstParamType && parameters[1].ParameterType == secondParamType;});
hasConversionMethod.Invoke(propertyBuilder, new[] { firstLambdaExp, secondLambdaExp });

这样就可以了, 其实那些 data annotation 也是这样子做出来,通过反射获取 Attribute 的值,然后调用 fluent api. 有了上面这个概念就可以写自己的 data annotation 啦~~

反射和表达式树是 c# 常用到的功能,大家可以多学学.

更新 : 2018-11-26

这里记入一下关于 foreignKey cascade action

默认情况下如果我们使用 data annotation

required + foreginkey . ef 会帮我们设计成 cascade delete

如果 foreignkey + nullable 就会是 cascade restrict.

如果使用 fluent api 的话就由我们设计了.

ef 6.x 有一个功能可以把所有的 cascade delete 停掉, ef core 不一样了

https://github.com/aspnet/EntityFrameworkCore/issues/3815

我看了一下 identity 也是有用 cascade delete 的,所以停到完好像不是 best practices.

所以我的规范是, 要 cascade delete 的话,可以用 data annotations

如果要限制的话,用 fluent api

fluent api 可以双向设置.

modelBuilder.Entity<QuestionVsSkill>().HasOne(e => e.skill).WithMany().HasForeignKey(e => e.skillId).OnDelete(DeleteBehavior.Restrict);
modelBuilder.Entity<Skill>().HasMany<QuestionVsSkill>().WithOne(e => e.skill).HasForeignKey(e => e.skillId).OnDelete(DeleteBehavior.Restrict);

上面 2 个是一样的结果.

注意 : 如果我们的 entity 有 navigation property 就要放, 如果没有就空 e.g. WithMany() <--params is empty

有一个比较难搞的东西,就是 database 循环引用, 比如我们有继承 table, foreignkey 就不支持 sql cascade null or delete 了

这时需要设置成 restrict 然后在处理的时候自己写程序实现 cascade null or delete.

Entity Framework 已经很多年了.

ef core 和 从前的 ef 6.x 用起来是差不多的.

ef core 的有点事跨平台,更好的性能,持续发展中 ...

ef 6.x 是功能比较齐全, 但是逐渐被淘汰了..

基本用法和从前是一样的, 比如

创建 DbContext, 定义 Entity 还有关系等等

namespace Project.Models
{public class DB : DbContext{public DB(DbContextOptions<DB> options) : base(options){}protected override void OnModelCreating(ModelBuilder modelBuilder){  }public virtual DbSet<Product> Products { get; set; }      }
}

在 startup.cs 里的 ConfigureServices 加入

    services.AddDbContext<SchoolContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

appsetting.json

"ConnectionStrings": {"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"//"DefaultConnection": "Server=192.168.1.152;Database=databaseName;User Id=username;Password=password;"
}

在 controller 依赖注入调用就可以了

public class HomeController : Controller
{public DB Db { get; set; }public HomeController(DB db) {Db = db;}public async Task<IActionResult> Index(){var products = await Db.Products.ToListAsync();return View();}
}

要生产 database 或需要 update database 可以使用 ef core 的工具 migrations

这个有点像是 version control 一样, 创建 migrations -> 工具会生产一个 Up 的代码和一个 Down 的代码 用于对数据库添加内容和移除内容.

自动生产以后,我们可以手动修改这些代码,然后 update database, 这样当我们 commit 的时候 Up 代码被执行, rollback 的时候 Down 代码被执行, 大概就是这个过程.

它是用命令来操作的, 打开 Package Manager Console

输入 add-migration init (或者 dotnet ef migrations add init)

init 是一个名字,可以随意放.

输入 update-database (或者 dotnet ef database update)

这时 Up 代码执行, 数据库就被更新了.

如果做错了要删除

输入 remove-migration (或者 dotnet ef migrations remove)

如果要 rollback 某个 version

输入 update-database somename

somename 就是你第一步我们为那一次 migrations 取得名字.

这样 Down 代码被执行,数据库成功还原了.

migrations 仅适合用于数据库架构的更新, 而不是数据库资料的更新哦.

多个 context 的时候,我们需要表示名字

add-migration ids -context PersistedGrantDbContext

或者 dotnet ef migrations add init --context applicationdbcontext

转载于:https://www.cnblogs.com/keatkeat/p/9296592.html

Asp.net core 学习笔记 ( ef core )相关推荐

  1. Nancy in .Net Core学习笔记 - 初识Nancy

    原文:Nancy in .Net Core学习笔记 - 初识Nancy 前言 去年11月份参加了青岛MVP线下活动,会上老MVP衣明志介绍了Nancy, 一直没有系统的学习一下,最近正好有空,就结合. ...

  2. EF Core学习笔记:关于主键 对IGuidGenerator的理解

    提要:公司项目使用Guid   聚集索引:聚集索引是索引结构和数据一起存放的索引.类似于字典的正文,当我们根据拼音直接就能找到那个字. 非聚集索引:非聚集索引是索引结构和数据分开存放的索引.类似于根据 ...

  3. EF Core学习笔记:反向工程 + 底层操作数据库原理

    EF core三种建模模式:DB first / Model first / Code first 反向工程:根据数据库表来反向生成实体类 应用场景:通过旧的数据库生成新的项目 命令: Scaffol ...

  4. 用ASP.NET Core MVC 和 EF Core 构建Web应用 (一)

    系统必备 .NET Core 2.0.0 SDK 或更高版本. 已安装 ASP.NET 和 Web 开发工作负载的 Visual Studio 2017 15.3 版或更高版本. 创建Web应用程序 ...

  5. 用于存储过程的ASP.NET Core Blazor和EF Core原始SQL查询

    目录 介绍 背景 先决条件 使用代码 创建数据库和表 步骤1:创建ASP.NET Core Blazor服务器应用程序 运行测试应用程序 步骤2:安装软件包 连接字符串 步骤3:建立模型类 创建DBC ...

  6. mysql多租户schema复制,Asp.net core下利用EF core实现从数据实现多租户(3): 按Schema分离 附加:EF Migration 操作...

    前言 前段时间写了EF core实现多租户的文章,实现了根据数据库,数据表进行多租户数据隔离. 今天开始写按照Schema分离的文章. 其实还有一种,是通过在数据表内添加一个字段做多租户的,但是这种模 ...

  7. .Net Core 学习笔记1——包、元包、框架

    .Net Core 是由NuGet包(package)组成的平台. 一起使用的多个包的集合:元包(Metapackage) package 包 (对应以前的程序集概念) Framework 框架 as ...

  8. ef core mysql 字符集,EF Core 基础知识

    数据库连接字符串 在 ASP.NET Core 添加配置片段: { "ConnectionStrings": { "BloggingDatabase": &qu ...

  9. EF Core 迁移过程遇到EF Core tools version版本不相符的解决方案

    如果你使用命令: PM> add-migration Inital 提示如下信息时: The EF Core tools version '2.1.1-rtm-30846' is older t ...

最新文章

  1. 小熊派4G cat1模块体验测试报告,AT命令发送短信拨号无脑教程,cat1移动网速测试...
  2. 照片边框 app android,Screener App-一手搞定将手机截图加上外框
  3. Gartner:2012年应用安全Hype Cycle
  4. jQuery学习之五---效果
  5. ubuntu mysql ftp_Ubuntu服务器安装ftp服务和MySQL数据库配置的一些记录
  6. 删除Ubuntu旧内核的几种方法,这下grub菜单看起来清爽多了!
  7. postman 使用
  8. 网络子系统34_网桥设备的传输与接收
  9. 计算机类教学期刊,热门大学计算机教学论文参考文献 大学计算机教学核心期刊参考文献哪里找...
  10. 《Neural Network and Deep Learning(神经网络与深度学习)》练习及问题详解
  11. Adobe Premiere基础-炫酷文字快闪(十四)
  12. Mongodb之Chunk研究
  13. 解决为什么电脑连接不上网络,应该如何查找问题
  14. Day3--搭建微信公众号管理系统
  15. ESP32-CAM、ESP8266、WIFI、蓝牙、单片机、热点创建嵌入式DNS服务器
  16. 爆!出现滑块验证码的原因找到了!
  17. LABVIEW学习之(1)读和写EXCEL
  18. 【K210】人脸识别 KPU-kpu.run_yolo2()函数说明
  19. 图像特征(三)——纹理特征(GLCM、LBP)
  20. 服务器维修合同样本,最新在线维修服务协议

热门文章

  1. read_csv读pima_data有感
  2. 路径字符串生成树形结构的思路_资源推荐!顶级程序员必刷宝典!LeetCode中文解题思路重磅问世!...
  3. IEEE-754单精度浮点类型有效数字理解(画图不易,望点赞支持)
  4. 7月4日云栖精选夜读:从《网安法》出发,给企业安全管理者的五条建议
  5. 数通工程师中,最多人拿10K-15K的工资,偷学他们是怎么发展的?
  6. unity的vr场景怎么做_怎么运用Unity制作VR全景漫游
  7. 【OpenCV--边缘检测】
  8. TensorFlow Object Detection API 技术手册(5)——制作自己的目标检测数据集
  9. Lua源码笔记--字符串连接
  10. 随着信息技术不断进步,智能制造面临快速发展的前景