EF Core 6 新功能汇总(二)

继上一篇之后,这一篇将给大家带来另外十个 EF Core 6 中的新功能特性,包括值转换器、脚手架和 DbContext 的改进等。

1HasConversion 支持值转换器

在 EF Core 6.0 中,HasConversion 方法的泛型重载方法可以指定内置或自定义的值转换器。

public class ExampleContext : DbContext
{public DbSet<Person> People { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Person>().Property(p => p.Address).HasConversion<AddressConverter>();}
}
public class Person
{public int Id { get; set; }public string FirstName { get; set; }public string LastName { get; set; }public Address Address { get; set; }
}
public class Address
{public string Country { get; set; }public string Street { get; set; }public string ZipCode { get; set; }
}
public class AddressConverter : ValueConverter<Address, string>
{public AddressConverter(): base(v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),v => JsonSerializer.Deserialize<Address>(v, (JsonSerializerOptions)null)){}
}

2简化多对多关系的配置

从 EF Core 6.0 开始,你可以在多对多的关系中配置一个连接实体,而无需任何额外的配置。另外,你可以配置一个连接实体,而不需要明确指定左右关系。
public class BloggingContext : DbContext
{public DbSet<Post> Posts { get; set; }public DbSet<Tag> Tags { get; set; }public DbSet<PostTag> PostTags { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Post>().HasMany(p => p.Tags).WithMany(t => t.Posts).UsingEntity<PostTag>();}protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=EFCore6Many2Many;Trusted_Connection=True;");
}
public class Post
{public int Id { get; set; }public string Name { get; set; }public List<Tag> Tags { get; set; } = new List<Tag>();
}
public class Tag
{public int Id { get; set; }public string Text { get; set; }public List<Post> Posts { get; set; } = new List<Post>();
}
public class PostTag
{public int PostId { get; set; }public int TagId { get; set; }public DateTime AddedDate { get; set; }
}

3脚手架多对多关系的改进

EF Core 6.0 改进了现有数据库的脚手架。它可以检测到连接表并为其生成多对多的映射。

如下示例数据库:

1f38b399461b1661ad2457a609f66b67.png

通过 CLI:

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EFCore6Many2Many" Microsoft.EntityFrameworkCore.SqlServer --context ExampleContext --output-dir Models

来自生成的 DbContextOnModelCreating

protected override void OnModelCreating(ModelBuilder modelBuilder)
{modelBuilder.Entity<Post>(entity =>{entity.HasMany(d => d.Tags).WithMany(p => p.Posts).UsingEntity<Dictionary<string, object>>("PostTag",l => l.HasOne<Tag>().WithMany().HasForeignKey("TagId"),r => r.HasOne<Post>().WithMany().HasForeignKey("PostId"),j =>{j.HasKey("PostId", "TagId")j.ToTable("PostTags")j.HasIndex(new[] { "TagId" }, "IX_PostTags_TagId");});});OnModelCreatingPartial(modelBuilder);
}

4脚手架生成可空引用类型

EF Core 6.0 改进了现有数据库的脚手架。当项目中启用了可空引用类型(NRT),EF Core 会自动用 NRT 构建 DbContext 和实体类型。

如实例表:

CREATE TABLE [Posts] ([Id] int NOT NULL IDENTITY,[Name] nvarchar(max) NOT NULL,[Description] nvarchar(max) NULL,CONSTRAINT [PK_Posts] PRIMARY KEY ([Id])
)

会生成模型:

public partial class Post
{public int Id { get; set; }public string Name { get; set; } = null!;public string? Desciption { get; set; }
}

5脚手架生成数据库注释

EF Core 6.0 将数据库注释与代码注释关联起来。

数据库例子:

CREATE TABLE [Posts] ([Id] int NOT NULL IDENTITY,[Name] nvarchar(max) NOT NULL,[Description] nvarchar(max) NULL,CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]));
EXEC sp_addextendedproperty@name = N'MS_Description', @value = 'The post table',@level0type = N'Schema', @level0name = dbo,@level1type = N'Table',  @level1name = Posts
EXEC sp_addextendedproperty@name = N'MS_Description', @value = 'The post identifier',@level0type = N'Schema', @level0name = dbo,@level1type = N'Table',  @level1name = Posts,@level2type = N'Column', @level2name = [Id];
EXEC sp_addextendedproperty@name = N'MS_Description', @value = 'The post name',@level0type = N'Schema', @level0name = dbo,@level1type = N'Table',  @level1name = Posts,@level2type = N'Column', @level2name = [Name];
EXEC sp_addextendedproperty@name = N'MS_Description', @value = 'The description name',@level0type = N'Schema', @level0name = dbo,@level1type = N'Table',  @level1name = Posts,@level2type = N'Column', @level2name = [Description];

生成的模型:

/// <summary>
/// The post table
/// </summary>
public partial class Post
{/// <summary>/// The post identifier/// </summary>public int Id { get; set; }/// <summary>/// The post name/// </summary>public string Name { get; set; }/// <summary>/// The description name/// </summary>public string Description { get; set; }
}

6AddDbContextFactory 注册 DbContext

在 EF Core 5.0 中,你可以注册一个工厂来手动创建 DbContext 实例。从 EF Core 6.0 开始,可用 AddDbContextFactory 注册 DbContext。所以你可以根据你的需要同时注入工厂和 DbContext。

var serviceProvider = new ServiceCollection().AddDbContextFactory<ExampleContext>(builder =>builder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database = EFCore6Playground")).BuildServiceProvider();var factory = serviceProvider.GetService<IDbContextFactory<ExampleContext>>();
using (var context = factory.CreateDbContext())
{// Contexts obtained from the factory must be explicitly disposed
}using (var scope = serviceProvider.CreateScope())
{var context = scope.ServiceProvider.GetService<ExampleContext>();// Context is disposed when the scope is disposed
}
class ExampleContext : DbContext
{ }

7无依赖性注入的 DbContext 池

在 EF Core 6.0 中,你可以使用没有依赖注入的 DbContext 池。PooledDbContextFactory 类型已经定义为 public 了。池是用 DbContextOptions 创建的,它将被用来创建 DbContext 实例。

var options = new DbContextOptionsBuilder<ExampleContext>().UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6Playground").Options;var factory = new PooledDbContextFactory<ExampleContext>(options);using var context1 = factory.CreateDbContext();
Console.WriteLine($"Created DbContext with ID {context1.ContextId}");
// Output: Created DbContext with ID e49db9b7-a0b0-4b54-8d0d-2cbd6c4cece7:1using var context2 = factory.CreateDbContext();
Console.WriteLine($"Created DbContext with ID {context2.ContextId}");
// Output: Created DbContext with ID b5a35bcb-270d-40f1-b668-5f76da1f35ad:1class ExampleContext : DbContext
{public ExampleContext(DbContextOptions<ExampleContext> options): base(options){}
}

8CommandSource 枚举

在 EF Core 6.0 中,新的枚举 CommandSource 已经被添加到 CommandEventData 类型中,提供给诊断源和拦截器。这个枚举值表明了 EF 的哪个部分创建了这个命令。

在 Db 命令拦截器中使用 CommandSource

class ExampleInterceptor : DbCommandInterceptor
{public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command,CommandEventData eventData, InterceptionResult<DbDataReader> result){if (eventData.CommandSource == CommandSource.SaveChanges){Console.WriteLine($"Saving changes for {eventData.Context.GetType().Name}:");Console.WriteLine();Console.WriteLine(command.CommandText);}if (eventData.CommandSource == CommandSource.FromSqlQuery){Console.WriteLine($"From Sql query for {eventData.Context.GetType().Name}:");Console.WriteLine();Console.WriteLine(command.CommandText);}return result;}
}

DbContext:

class ExampleContext : DbContext
{public DbSet<Product> Products { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6CommandSource").AddInterceptors(new ExampleInterceptor());
}
class Product
{public int Id { get; set; }public string Name { get; set; }public decimal Price { get; set; }
}

Program:

using var context = new ExampleContext();context.Products.Add(new Product { Name = "Laptop", Price = 1000 });
context.SaveChanges();var product = context.Products.FromSqlRaw("SELECT * FROM dbo.Products").ToList();/* Output:
Saving changes for ExampleContext:SET NOCOUNT ON;
INSERT INTO[Products] ([Name], [Price])
VALUES(@p0, @p1);
SELECT[Id]
FROM[Products]
WHERE @@ROWCOUNT = 1 AND[Id] = scope_identity();From Sql query for ExampleContext:SELECT* FROM dbo.Products
*/

9值转换器允许转换空值

在 EF Core 6.0 中,值转换器允许转换空值。当你有一个未知值的枚举,并且它在表中表示一个可空的字符串列时,这很有用。

public class ExampleContext : DbContext
{public DbSet<Dog> Dogs { get; set; }protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<Dog>().Property(c => c.Breed).HasConversion<BreedConverter>();}protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder){optionsBuilder.EnableSensitiveDataLogging().LogTo(Console.WriteLine).UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=EFCore6ValueConverterAllowsNulls;");}
}
public enum Breed
{Unknown,Beagle,Bulldog
}
public class Dog
{public int Id { get; set; }public string Name { get; set; }public Breed? Breed { get; set; }
}
public class BreedConverter : ValueConverter<Breed, string>
{
#pragma warning disable EF1001public BreedConverter(): base(v => v == Breed.Unknown ? null : v.ToString(),v => v == null ? Breed.Unknown : Enum.Parse<Breed>(v),convertsNulls: true){}
#pragma warning restore EF1001
}

但要注意,这里面有陷阱。详情请见链接:

https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-6.0/whatsnew#allow-value-converters-to-convert-nulls

10明确设置临时值

在 EF Core 6.0 中,你可以在实体被追踪之前显式地给它们设置临时值。当值被标记为临时值时,EF 将不会像以前那样重置它。

using var context = new ExampleContext();Blog blog = new Blog { Id = -5 };
context.Add(blog).Property(p => p.Id).IsTemporary = true;var post1 = new Post { Id = -1 };
var post1IdEntry = context.Add(post1).Property(e => e.Id).IsTemporary = true;
post1.BlogId = blog.Id;var post2 = new Post();
var post2IdEntry = context.Add(post2).Property(e => e.Id).IsTemporary = true;
post2.BlogId = blog.Id;Console.WriteLine($"Blog explicitly set temporary ID = {blog.Id}");
Console.WriteLine($"Post 1 explicitly set temporary ID = {post1.Id} and FK to Blog = {post1.BlogId}");
Console.WriteLine($"Post 2 generated temporary ID = {post2.Id} and FK to Blog = {post2.BlogId}");// Output:
// Blog explicitly set temporary ID = -5
// Post 1 explicitly set temporary ID = -1 and FK to Blog = -5
// Post 2 generated temporary ID = -2147482647 and FK to Blog = -5class Blog
{public int Id { get; set; }
}
class Post
{public int Id { get; set; }public int BlogId { get; set; }
}
class ExampleContext : DbContext
{public DbSet<Blog> Blogs { get; set; }public DbSet<Post> Posts { get; set; }protected override void OnConfiguring(DbContextOptionsBuilder options)=> options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6TempValues");
}

11结尾

本文所有代码示例都可以在我的 GitHub 中找到:

https://github.com/okyrylchuk/dotnet6_features/tree/main/EF%20Core%206#miscellaneous-enhancements

原文:bit.ly/3G6Yt3m
作者:Oleg Kyrylchuk
翻译:精致码农

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291976.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux之lsusb命令和cd -命令使用总结

1、lsusb命令介绍 使用 lsusb 来列出 USB 设备和它的属性,lsusb 会显示驱动和内部连接到你系统的设备。直接在控制台输入 lsusb 即可 2、lsusb简单使用 在控制台输入 lsusb 效果如下 系统中同时使用了 USB 2.0 root hub 驱动和 USB 3.0 root hub 驱动。 bus 002 指明设备…

Fiddler (五) Mac下使用Fiddler

http://www.cnblogs.com/TankXiao/archive/2013/04/18/3027971.html Fiddler是用C#开发的。 所以Fiddler不能在Mac系统中运行。 没办法直接用Fiddler来截获MAC系统中的HTTP/HTTPS, Mac 用户怎么办呢&#xff1f; Fiddler可以允许“远程连接”。 我们可以利用这个间接来实…

她花了8个月让骗子爱上自己,然后把骗子引到警察局......

1 相信你一定可以的&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 凤凰传奇的buff有多强&#xff1f;&#xff08;via.段子楼&#xff0c;侵删&#xff09;▼3 老板的名字实在太有味道了&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 被微信骰子气死…

mysql配置-django

mysql配置&#xff0d;django (python) 数据库配置 像前面章节提到的 模版路径一样&#xff0c;数据库配置也是在Django的配置文件里&#xff0c;缺省 是 settings.py 。 打开这个文件并查找数据库配置&#xff1a; DATABASES {default: {ENGINE: django.db.backends.sqlite3,…

精彩回顾|2021 中国 .NET 开发者峰会

.NET Conf China 2021 是面向开发人员的社区峰会&#xff0c;基于 .NET Conf 2021&#xff0c;庆祝 .NET 6 的发布和回顾过去一年来 .NET 在中国的发展。峰会由来自北京、上海、苏州、深圳、武汉、广州、青岛、烟台、杭州等各地区的 .NET 技术社区共同发起举办&#xff0c;由微…

wms地图绘制工具_移情地图,了解用户需求的利器

如果你想打造一款成功的产品&#xff0c;对你的用户有一个良好的了解是至关重要的。虽然用户体验设计师有许多技能可以帮助他们发展这种理解&#xff0c;但有一种关键技能有很多优势&#xff0c;它称为移情地图。User-Experience Quiz: 2018 UX Year in Review(NN/g)中有一题问…

linux之openssl简单介绍

OpenSSL 是一个强大的安全套接字层密码库&#xff0c;囊括主要的密码算法、常用的密钥和证书封装管理功能及SSL协议&#xff0c;并提供丰富的应用程序供测试或其它目的使用。在OpenSSL被曝出现严重安全漏洞后&#xff0c;发现多数通过SSL协议加密的网站使用名为OpenSSL的开源软…

把准脉搏 U-Mail邮件系统2014开足马力

为什么80%的码农都做不了架构师&#xff1f;>>> 马年春节即将来临&#xff0c;在过去的一年&#xff0c;U-Mail邮件服务器从用户需求出发&#xff0c;围绕着为用户打造稳定、安全、高效、易操作、助管理的邮件系统目标&#xff0c;三军用命&#xff0c;取得了不俗业…

kdbchk: the amount of space used is not equal to block size

一.对数据文件检查 注意&#xff1a;应该在关闭数据库模式下进行bbed的操作 [oracleora10 controlfile]$ dbv file/u01/app/oracle/oradata/ORCL/datafile/test_01.dbf blocksize8192DBVERIFY: Release 10.2.0.1.0 - Production on Fri Jan 16 23:05:01 2015Copyright (c) 198…

Maven私服的简单搭建教程(Nexus)

2019独角兽企业重金招聘Python工程师标准>>> 第一步&#xff0c;下载nexus的安装包并解压 链接&#xff1a;http://pan.baidu.com/s/1jIhpZ98 密码&#xff1a;6bqx 如果不能下载给我私信&#xff0c;最近也一直在想把这些东西方github上&#xff0c;但是想想自己老…

linux之修改dns以及用netmask修改ip和网关

1、介绍netmask netmaks可以在 IP范围、子网掩码、cidr、cisco等格式中互相转换&#xff0c;并且提供了IP地址的点分十进制、16进制、8进制、2进制之间的互相转换&#xff01; 2、安装netmask sudo apt-get install netmask 3、修改ip 把ip修改成192.168.1.18 ifconfig eth0 1…

如何使用 .NET 实现高效的网络连接性检查?

咨询区 Mohit Deshpande我的项目有一个需求&#xff0c;需要检查网络的连通性&#xff0c;请问是否有高效的方式去实现&#xff1f;回答区 Leo虽然并不能完全可靠的实现网络连通性检查&#xff0c;因为你不能保证目标机永远在线&#xff0c;相比来说更高效的方式是用 Ping协议 …

el-popover超过固定高度后出现滚动条_「测绘精选」RTK测量不出现固定解的原因...

摘要&#xff1a;在日常RTK测量的应用中&#xff0c;时常不出现固定解的情况&#xff0c;导致测量测绘工作无法按时完成或者测量测绘结果精度无法保证。本文将从基准站、移动站、数据链等三个方面进行分析。随着卫星定位技术的快速发展&#xff0c;人们对快速高精度位置信息的需…

史上最牛物理科普

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…

在Android中afinal框架下实现sqlite数据库版本升级的办法

上一篇文章采用的是SQLiteOpenHelper中的onUpgrade方法实现数据库的升级。 首先获取Context&#xff1a; private Context mContextthis; 然后实现FinalDb内的静态方法&#xff1a; FinalDb.create(mContext,"afinal.db",true,2,this); 实现FinalDb的DbUpdateListe…

MySQL备份原理详解

备份是数据安全的最后一道防线&#xff0c;对于任何数据丢失的场景&#xff0c;备份虽然不一定能恢复百分之百的数据(取决于备份周期)&#xff0c;但至少能将损失降到最低。衡量备份恢复有两个重要的指标&#xff1a;恢复点目标(RPO)和恢复时间目标(RTO)&#xff0c;前者重点关…

计时器小程序——由浅入深实例讲解

本菜在实现简单的计时器过程中遇到问题的一些成长笔记&#xff0c;有不完整观点的话请多多见谅&#xff0c;也看了众多大神的博客才整理的笔记&#xff0c;下面来实现个人写的小程序。 首先第一个实例&#xff08;很简单&#xff09;&#xff1a; winform窗体包含两个控件&…

linux c之通过管道实现兄弟间进程通信:

1、兄弟间进程通信&#xff1a; 父进程创建管道&#xff0c;并使用fork函数创建2个进程&#xff0c;在第一个子进程发消息到第二个子进程&#xff0c;第2个子进程读取消息并处理&#xff0c;在父进程中不使用管道通信&#xff0c;所以什么都不做&#xff0c;直接关闭管道两端并…

理解 Azure AD 安全默认值设置

为了保护广大的Microsoft 365用户的安全&#xff0c;Azure AD在某些情况下会启用安全默认值&#xff0c;就是要求所有的账号都启用MFA。MFA的全称是 Multi-factor Authentication&#xff0c;中文翻译为多因子身份验证&#xff0c;就是说除了账号密码之外&#xff0c;添加额外的…