介绍
接下来我将给大家重点介绍一下.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