EF Core 6 新功能匯總(四)

EF Core 6 新功能匯總(四)

在這篇文章中,你將看到 EF Core 對 SQLite、In-memory 提供者和 EF.Functions.Contains 方法的改進。

最後更新 2022/6/2 下午10:12
liamwang 精致码农
預計閱讀 5 分鐘
分類
EF Core
標籤
.NET C# EF Core ORM SQLite

在這篇文章中,你將看到 EF Core 對 SQLite、In-memory 提供者和 EF.Functions.Contains 方法的改進。

這是 EF Core 6 新功能彙總的第四篇文章:

1 SQLite 支援 DateOnly 和 TimeOnly

在 EF Core 6.0 中,SQLite 提供者支援新的 DateOnlyTimeOnly 型別。它將它們儲存為 TEXT

using var context = new ExampleContext();

var query1 = context.People
    .Where(p => p.Birthday < new DateOnly(2000, 1, 1))
    .ToQueryString();

Console.WriteLine(query1);
// SELECT "p"."Id", "p"."Birthday", "p"."Name"
// FROM "People" AS "p"
// WHERE "p"."Birthday" < '2000-01-01'

var query2 = context.Notifications
    .Where(n => n.AllowedFrom >= new TimeOnly(8, 0) && n.AllowedTo <= new TimeOnly(16, 0))
    .ToQueryString();

Console.WriteLine(query2);
// SELECT "n"."Id", "n"."AllowedFrom", "n"."AllowedTo"
// FROM "Notifications" AS "n"
// WHERE("n"."AllowedFrom" >= '08:00:00') AND("n"."AllowedTo" <= '16:00:00')

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateOnly Birthday { get; set; }
}
class Notification
{
    public int Id { get; set; }
    public TimeOnly AllowedFrom { get; set; }
    public TimeOnly AllowedTo { get; set; }
}
class ExampleContext : DbContext
{
    public DbSet<Person> People { get; set; }
    public DbSet<Notification> Notifications { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite(@"Data Source=Db\DateOnlyTimeOnly.db");
}

2 SQLite 連線是池化的

SQLite 資料庫是一個檔案。因此,在大多數情況下,建立一個連線是很快的。然而,開啟一個加密資料庫的連線會非常慢。因此,在 EF Core 6 中,SQLite 連線現在是池化的,就像其他資料庫提供者一樣。

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}
class ExampleContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=EncryptedDb.db;Mode=ReadWriteCreate;Password=password");
}

3 SQLite 中的命令逾時

在 EF Core 6 的 SQLite 中,支援新增 Command Timeout 命令到連線字串中,你可以用它來指定 SQLite 的預設逾時時間。

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
}
class ExampleContext : DbContext
{
    public DbSet<Person> People { get; set; }

    // 60 seconds as the default timeout for commands created by connection
    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlite("Data Source=Test.db;Command Timeout=60");
}

4 SQLite 中的儲存點

在 EF Core 6.0 中,SQLite 支援儲存點 (Savepoints)。你可以儲存、回滾和釋放儲存點。

var dbPath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..\\..\\..\\Savepoints.db"));

using var connection = new SqliteConnection($"Data Source={dbPath}");
connection.Open();
using var transaction = connection.BeginTransaction();

// The insert is committed to the database
using (var command = connection.CreateCommand())
{
    command.CommandText = @"INSERT INTO People (Name) VALUES ('Oleg')";
    command.ExecuteNonQuery();
}

transaction.Save("MySavepoint");

// The update is not commited since savepoint is rolled back before commiting the transaction
using (var command = connection.CreateCommand())
{
    command.CommandText = @"UPDATE People SET Name = 'Not Oleg' WHERE Id = 1";
    command.ExecuteNonQuery();
}

transaction.Rollback("MySavepoint");
transaction.Commit();

5 記憶體資料庫驗證必要屬性

在 EF Core 6.0 中,記憶體 (In-memory) 資料庫驗證了必要(Required)的屬性。如果你試圖儲存一個實體的必要屬性值為空,就會出現例外狀況。如果有必要,你可以停用這個驗證。

using var context = new ExampleContext();

var blog = new Blog();
context.Blogs.Add(blog);

await context.SaveChangesAsync();
// Unhandled exception. Microsoft.EntityFrameworkCore.DbUpdateException:
// Required properties '{'Title'}' are missing for the instance of entity
// type 'Blog' with the key value '{Id: 1}'.

class Blog
{
    public int Id { get; set; }
    [Required]
    public string Title { get; set; }
}
class ExampleContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options
        .EnableSensitiveDataLogging()
        .LogTo(Console.WriteLine, new[] { InMemoryEventId.ChangesSaved })
        .UseInMemoryDatabase("ValidateRequiredProps");

    //  To disable the validation
    //  .UseInMemoryDatabase("ValidateRequiredProps", b => b.EnableNullChecks(false));
}

6 EF.Functions.Contains 方法

在 EF Core 6.0 中,你可以使用 EF.Functions.Contains 方法來處理使用值轉換器對應的資料行(也可以處理二進位資料行)。

using var context = new ExampleContext();

var query = context.People
    .Where(e => EF.Functions.Contains(e.FullName, "Oleg"))
    .ToQueryString();

Console.WriteLine(query);
// SELECT[p].[Id], [p].[FullName]
// FROM[People] AS[p]
// WHERE CONTAINS([p].[FullName], N'Oleg')

class Person
{
    public int Id { get; set; }
    public FullName FullName { get; set; }
}
public class FullName
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}
class ExampleContext : DbContext
{
    public DbSet<Person> People { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Person>()
            .Property(x => x.FullName)
            .HasConversion(
                v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
                v => JsonSerializer.Deserialize<FullName>(v, (JsonSerializerOptions)null));
    }

    protected override void OnConfiguring(DbContextOptionsBuilder options)
        => options.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFCore6Contains");
}

7 結尾

本文所有程式碼範例都可以在我的 GitHub 中找到:https://github.com/okyrylchuk/dotnet6_features/tree/main/EF%20Core%206#miscellaneous-enhancements

原文:https://blog.okyrylchuk.dev/entity-framework-core-6-features-part-3

作者:Oleg Kyrylchuk

翻譯:精緻碼農

繼續探索

延伸閱讀

更多文章