当然不要忘记,官网才是最好的老师:docs.microsoft.com/zh-cn/dotnet/core/
沙盒学习指南: 免费环境docs.microsoft.com/zh-cn/learn/browse
posted @ 2020 初久的私房菜 推荐出品

EF 6 新特性六

 

正文

介绍

接下来我将给大家重点介绍一下.Net 6 之后的一些新的变更,文章都是来自于外国大佬的文章,我这边进行一个翻译,并加上一些自己的理解和解释。

源作者链接:https://blog.okyrylchuk.dev/entity-framework-core-6-features-part-2

正文

没有依赖注入的 DbContext 池化

在 EF Core 6.0 中,您可以使用DbContext池而无需依赖注入。PooledDbContextFactory类型已公开。该池是使用DbContextOptions的实例创建的,该实例将用于创建上下文实例。

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:1

using var context2 = factory.CreateDbContext();
Console.WriteLine($"Created DbContext with ID {context2.ContextId}");
// Output: Created DbContext with ID b5a35bcb-270d-40f1-b668-5f76da1f35ad:1

class ExampleContext : DbContext
{
    public ExampleContext(DbContextOptions<ExampleContext> options)
        : base(options)
    {
    }
}

命令源枚举

在 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;
    }
}

数据库上下文:

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; }
}

程序:

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
*/

值转换器允许转换空值

在 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 EF1001
    public BreedConverter()
        : base(
            v => v == Breed.Unknown ? null : v.ToString(),
            v => v == null ? Breed.Unknown : Enum.Parse<Breed>(v),
            convertsNulls: true)
    {
    }
#pragma warning restore EF1001
}

但要注意,它有陷阱。详情按链接

显式设置临时值

在 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 = -5

class 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");
}

结语

联系作者:加群:867095512 @MrChuJiu

公众号

posted @   初久的私房菜  阅读(336)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
作者:初久的私房菜
好好学习,天天向上
返回顶部小火箭
好友榜:
如果愿意,把你的博客地址放这里
张弛:https://blog.zhangchi.fun/
点击右上角即可分享
微信分享提示