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 被微信骰子气死…

精彩回顾|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)中有一题问…

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

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

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

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

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

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

史上最牛物理科普

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

MySQL备份原理详解

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

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;添加额外的…

能抗 6 级风的「拇指伞」,晴雨两用、揣兜就走!

▲ 点击查看每到这个季节&#xff0c;天气就开始对人类不友好了&#xff1a;要么万里无云&#xff0c;紫外线爆表&#xff1b;要么忽然乌云密布&#xff0c;狂风暴雨。出门带伞&#xff0c;谁不知道&#xff0c;说着简单&#xff0c;可是普通的雨伞大小很尴尬&#xff0c;手里不…

SecureCRT 中 python 命令行使用退格键(backspace)出现 ^H 解决办法

选项-->会话选项-->映射键 勾选“其他映射”中的两个选择框 转载于:https://www.cnblogs.com/RUReady/p/6165289.html

云计算基本概念

IT技术行业最不缺少的就是概念的炒作&#xff0c;今天出来个新技术名词&#xff0c;明天又出来个新技术名词&#xff0c;搞的从业人员焦虑不堪&#xff0c;生怕被这个时代所抛弃&#xff1b;但是人的精力是有限的&#xff0c;不可能什么都去学习&#xff0c;与其整天被这一帮发…

通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存...

很久没有更新dapr系列了。今天带来的是一个小的组件集成&#xff0c;通过多级缓存框架来实现对服务的缓存保护&#xff0c;依旧是一个简易的演示以及对其设计原理思路的讲解&#xff0c;欢迎大家转发留言和star目录&#xff1a;一、通过Dapr实现一个简单的基于.net的微服务电商…

年纪都这么大了,还在倒班工作......

1 这么大年纪都在倒班工作&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 原来&#xff0c;这就是命啊&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 天啊&#xff0c;都是什么狗血剧情&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xf…

javascript的关于刷新页面给出提示框的代码

// 页面刷新事件 ,或者关闭事件的3中方法&#xff01;测试都可以&#xff01;参考官方文档&#xff1a; https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers.onbeforeunloadhttps://developer.mozilla.org/en-US/docs/Web/API 方法1&#xff1a;window.onb…

JavaScript格式化数字显示格式

为什么80%的码农都做不了架构师&#xff1f;>>> JavaScript格式化数字显示格式 /** * 格式化数字显示方式 * 用法 * formatNumber(12345.999,#,##0.00); * formatNumber(12345.999,#,##0.##); * formatNumber(123,000000); * param num * param pattern */ func…