EF Core – 大杂烩
前言
记入一些零零碎碎的知识。
Shadow Properties
参考:Docs – Shadow and Indexer Properties
Shadow Property 指的是那些在数据库有 Column 但是在 Entity Class 却没有 Property 的 Property。
Foreign key example
举例
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = "";
public List<Color> Colors = [];
} public class Color
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int ProductId { get; set; }
public Product Product { get; set; } = null!;
}
有 2 个 Entity -- Product 和 Color,它们的关系是一对多。在数据库 Color Table 里一定要记入一个 foreign key ProductId,这样它俩才能关联在一起。
在 Entity Class,关联 Product 和 Color 的是 Product.List<Color> 和 Color.Product 属性,Color.ProductId 属性是多余的。
这个多余的 ProductId 就很符合 Shadow Property 的理念 -- 数据库有 Column 但是在 Entity Class 却没有 Property。
具体做法很简单,首先把 ProductId 从 class Color 中移除
public class Color
{
public int Id { get; set; }
public string Name { get; set; } = "";
// public int ProductId { get; set; } // 不需要了
public Product Product { get; set; } = null!;
}
然后在设置 Fluent API 时 HasForeignKey 直接写 string "ProductId"。
modelBuilder.Entity<Color>()
.HasOne(e => e.Product)
.WithMany(e => e.Colors)
// .HasForeignKey(e => e.ProductId) 把 e => e.ProductId 改成 "ProductId"
.HasForeignKey("ProductId")
.OnDelete(DeleteBehavior.Cascade);
这样 ProductId 就变成 Shadow Property 了。
using var db = new ApplicationDbContext();
var colorEntity = db.Model.GetEntityTypes().Single(e => e.ClrType == typeof(Color));
var productIdProperty = colorEntity.GetProperty("ProductId");
Console.WriteLine("is shadow: " + productIdProperty.IsShadowProperty()); // is shadow: true
Config and access shadow properties
config shadow property
上面例子中,我们利用 HasForeignKey 间接设置了 Shadow Property。
我们来一个直接的。
modelBuilder.Entity<Color>().Property<DateTimeOffset>("LastUpdated");
使用 Property 方法,提供一个类型和一个 name 就可以了,后续要链接上 HasMaxLength,HasPrecision,HasColumnName 都可以。
access shadow property
LastUpdated shadow property 不在 class 里,那要怎样 set value 呢?
答案是通过 entry property 直接 set CurrentValue
using var db = new ApplicationDbContext();
var color = new Color { Name = "red" };
db.Entry(color).Property("LastUpdated").CurrentValue = DateTimeOffset.Now;
db.Colors.Add(color);
db.SaveChanges();
通常这些逻辑会写在 Entity Interception 里。
Backing Fields
下面是一个 Order Entity
public class Order
{
public int Id { get; set; } private string _name = "";
public string Name
{
get { return _name; }
set { _name = value; }
}
}
它的特别之处在于,它有一个 field _name,然后有 getter setter Property Name。
有时候在 Application Level 我们想使用 getter setter 做一些额外处理,但又不希望 Database Layer 受到影响。
这时就可以使用 Backing Fields,它可以让 Entity 和 数据库映射的时候不使用 Name Property,而是直接使用 _name Field。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>(
builder =>
{
builder.ToTable("Order");
builder.Property(e => e.Name).HasField("_name").UsePropertyAccessMode(PropertyAccessMode.Field);
});
}
告诉它,Order 有一个 Property Name,它有一个 Field _name,访问的时候使用 Field。
query 数据后会实例化 Order,这个时候它会直接写入 _name 而不是通过 Name setter。
在 translate SQL command 的时候会直接访问 _name value,而不是 Name getter。
PropertyAccessMode 是 Enum,它有好几个选项可以分开控制 query 数据时和 translate SQL command 时要用 Field 还是 Property。

AsAsyncEnumerable
在 ASP.NET Core – ADO.NET 文章中,我们有提到

SQL 返回的 data 是 stream 来的,读的时候是一条一条异步读取的。
这种读取方式的好处是可以在数据还没有加载完之前,就开始对已加载的数据做处理。
然而 EF Core ToListAsync 是把 reader 读到完放进 List 里面以后才让我们使用。
var products = await db.Products.ToListAsync();
在 C# 8.0 之前,我们无法透过 EF Core 使用到 ADO.NET async read row by row 的好处。
直到 C# 8.0 推出 Iterating with Async Enumerables 后才可以。
using var db = new ApplicationDbContext(); var products = db.Products.AsAsyncEnumerable(); await foreach (var product in products)
{
Console.WriteLine(product.Name);
}
AsAsyncEnumerable + await foreach 就等价于 ADO.NET 的 whilte (await reader.ReadAsync)。
在 ADO.NET reader 还没有读取完毕之前,我们就可以拿到已读取的 entity 做操作了。
IAsyncEnumerable to List
有些 Library 会因为担心性能而选择 return IAsyncEnumerable,出发点是好,但是对于使用者来说,未必是件好事,因为 IAsyncEnumerable 比 List 难用多了。
于是,就有了 IAsyncEnumerable 转换成 List 的需求。
我们可以使用一个 Library 做到这个事情 -- System.Linq.Async (它是 Rx.NET 派系的一员)
dotnet add package System.Linq.Async
var products = await db.Products.AsAsyncEnumerable().ToListAsync();
Console.WriteLine(products.Count);
它扩展了 IAsyncEnumerable 接口,让它多了 ToListAsync 方法可以用。
它的具体实现很简单,就是 for loop 放进 List 里面,源码在 ToList.cs

EF Core – 大杂烩的更多相关文章
- EF Core 数据库迁移(Migration)
工具与环境介绍 1.开发环境为vs 2015 2.mysql EF Core支持采用 Pomelo.EntityFrameworkCore.MySql 源代码地址(https://github. ...
- Asp.net Core 通过 Ef Core 访问、管理Mysql
本文地址:http://www.cnblogs.com/likeli/p/5910524.html 环境 dotnet Core版本:1.0.0-preview2-003131 本文分为Window环 ...
- EF Core 杂记
本系列文章,将介绍本人在学习和使用EF Core的过程中的收获与心得. 或许有的地方讲的错误 欢迎大家批评指出. 1.EF Core 数据库迁移(Migration)
- MySQL官方.NET Core驱动已出,支持EF Core
千呼万唤始出来MySQL官方.NET Core驱动已出,支持EF Core. 昨天MySQL官方已经发布了.NET Core 驱动,目前还是预览版,不过功能已经可用. NuGet 地址:https:/ ...
- EF Core 1.0 和 SQLServer 2008 分页的问题
EF Core 1.0 在sqlserver2008分页的时候需要指定用数字分页. EF Core1.0 生成的分页语句中使用了 Featch Next.这个语句只有在SqlServer2012的时候 ...
- EntityFramework Core技术线路(EF7已经更名为EF Core,并于2016年6月底发布)
官方文档英文地址:https://github.com/aspnet/EntityFramework/wiki/Roadmap 历经延期和更名,新版本的实体框架终于要和大家见面了,虽然还有点害羞.请大 ...
- EF Core CodeFirst实践 ( 使用MS SqlServer)
这里使用 MS SQLSERVER ,网上大多使用 SQLite 先来一个CodeFirst 新建项目 这里我们选择 ASP.NET Core Web Application (.NET Core) ...
- ASP.NET Core 开发-Entity Framework (EF) Core 1.0 Database First
ASP.NET Core 开发-Entity Framework Core 1.0 Database First,ASP.NET Core 1.0 EF Core操作数据库. Entity Frame ...
- ASP.NET Core 开发 - Entity Framework (EF) Core
EF Core 1.0 Database First http://www.cnblogs.com/linezero/p/EFCoreDBFirst.html ASP.NET Core 开发 - En ...
- 再谈EF Core内存数据库单元测试问题
(此文章同时发表在本人微信公众号"dotNET每日精华文章",欢迎右边二维码来关注.) 题记:在用EF Core的内存数据库进行单元测试的时候遇到"无法访问已释放的对象& ...
随机推荐
- 四 黑马程序员-java面向对象(上)
一.:面向对象 (1)面向对象:是基于面向过程的一种思想. 面向过程:以函数为基础,关注实现过程. 面向对象:以对象为基础,关注实现结果. (2)面向对象的思想特点: A:是一种更符合人们思考习惯的思 ...
- Python爬取小说+Servlet+C3P0+MVC构建小说api
一.摘要: 使用python爬取网络小说数据存入数据库,利用C3P0数据库连接池获取数据库数据,采用MVC三层架构对数据库数据进行操作,输出JSON格式数据到前端页面 二.内容: 1.gitee外链消 ...
- 疑难杂症(已解决) | 为什么出现python中tkinter创建界面需要一闪而过才进入主窗口?
一.具体问题 如图所示,我编写了一个主窗口的程序(如下所示,有兴趣的可以自己复制后运行),发现需要先进入第一个窗口再进入主界面,这不符合逻辑. 代码区域(完整代码): from tkinter imp ...
- tp6 uniapp跨越问题
自己写一个简单的中间件
- tp5.1--数据库事务操作
https://blog.csdn.net/qq_42176520/article/details/88708395 使用事务处理的话,需要数据库引擎支持事务处理.比如 MySQL 的 MyISAM ...
- Git 清除缓存账密
[已解决] git push 报错:git: 'credential-manager' is not a git command. See 'git --help'. 解决方案1)运行 git con ...
- 适用于 .NET 的现代化、流畅、可测试的HTTP客户端库
前言 今天大姚给大家分享一个.NET开源(MIT License).免费.现代化.流畅.可测试.可移植的URL构建器和HTTP客户端库:Flurl. 项目介绍 Flurl是一个集现代性.流畅性.异步性 ...
- 解决react native打包apk文件安装好之后进入应用闪退的问题
这个是我一个前端前辈帮我弄的,自己解决的时候不行,她去官网找了相关的问题,然后发给我的. react-native android 的release安装包运行闪退,但是debug运行正常 环境:0.6 ...
- 洛谷[NOIP2015 普及组] 金币
[NOIP2015 普及组] 金币 题目背景 NOIP2015 普及组 T1 题目描述 国王将金币作为工资,发放给忠诚的骑士.第一天,骑士收到一枚金币:之后两天(第二天和第三天),每天收到两枚金币:之 ...
- Golang 高性能 Websocket 库 gws 使用与设计(一)
前言 大家好这里是,白泽,这期分析一下 golang 开源高性能 websocket 库 gws. 视频讲解请关注B站:白泽talk 介绍 gws:https://github.com/lxzan/g ...