簡體   English   中英

創建表后 EFCore EnsureCreated() 運行命令

[英]EFCore EnsureCreated() run command after table creation

所以我對 EFCore 很陌生(直接進入 5.0 預覽版,因為為什么不),並且享受所有流暢的配置方面的事情。 整個IEntityTypeConfiguration<>概念確實有助於使實體與后備數據庫無關(而不是在實體本身上使用屬性)。

我在Startup.cs中使用DbContext.Database.EnsureCreated()生成整個數據庫。 它目前由 SQLite 支持,而我正在玩,但最終希望通過 TimescaleDB 擴展遷移到 PostgreSQL。

問題是,在使用 TimescaleDB 時,我需要在創建表本身后立即發出create_hypertable()

創建表后發出命令的最佳方法是什么?

  • EnsureCreated()之后,使用ExecuteSqlRaw()嗎? 這意味着在執行 SQL 之前已經創建了所有表。 我希望它盡可能接近表創建。
  • DbContext內部的某個地方?
  • 在我的IEntityTypeConfiguration<>
  • 或者別的地方?

謝謝!

如果您想繼續使用context.Database.EnsureCreated() ,那么在調用之后運行您自己的腳本(例如,通過執行context.Database.ExecuteSqlRaw() )是 go 的方式。

這意味着在執行 SQL 之前已經創建了所有表。 我希望它盡可能接近表創建。

據我所知,這不應該有任何缺點,因此通過將create_hypertable()調用移近另一個表,您不會獲得任何好處(如果您不同意,請詳細說明為什么會這樣)。


如果您出於某種原因確實想將呼叫移至另一個命令附近,則可以實現DbCommandInterceptor 然后,您可以解析特定CREATE TABLE語句或其他內容的命令文本,然后發出您自己的語句。 (如果你想 go 這條路線,發表評論,我用一些代碼更新這個答案。)


如果你從使用context.Database.EnsureCreated()切換到遷移,你可以使用Sql()方法來注入你自己的語句:

public partial class MyMigration : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.Sql("SELECT create_hypertable('conditions', 'time');")
    }
}

也許您可以詳細說明一下,為什么您覺得需要將create_hypertable()調用移近他們的表。


如果您只關心在 C# 代碼中關閉create_hypertable()調用,但不一定在生成的 SQL 代碼中,然后引入自定義屬性(或接口)和將超表應用於所有具有修飾屬性的實體的方法使用此屬性(或實現此接口)可能就足夠了:

[AttributeUsage(AttributeTargets.Property)]
public class HypertableColumnAttribute : Attribute
{
}

public static class DbContextExtensions
{
    public static void ApplyHypertables(this Context context)
    {
        var entityTypes = context.Model.GetEntityTypes();

        foreach (var entityType in entityTypes)
        {
            foreach (var property in entityType.GetProperties())
            {
                if (property.ClrType.GetCustomAttribute(
                    typeof(HypertableColumnAttribute)) != null)
                {
                    var tableName = entityType.GetTableName();
                    var columnName = property.GetColumnName();

                    context.Database.ExecuteSqlInterpolated(
                        $"SELECT create_hypertable({tableName}, {columnName});");
                }
            }
        }
    }
}

public class IceCream
{
    public int IceCreamId { get; set; }
    public string Name { get; set; }

    [HypertableColumn]
    public DateTime? UpdatedAt { get; set; }
}

public class Context : DbContext
{
    public DbSet<IceCream> IceCreams { get; set; }

    /// ...
}

internal static class Program
{
    private static void Main()
    {
        using var context = new Context();

        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
        context.ApplyHypertables();

        var iceCreams = context.IceCreams
            .OrderBy(i => i.IceCreamId)
            .ToList();
        
        Debug.Assert(iceCreams.Count == 2);
    }
}

如果您想保持 model 類沒有任何數據庫特定屬性,則可以使用注釋。 想法基本相同,但注釋是 EF Core 元數據,可以使用HasAnnotation()方法定義為IEntityTypeConfiguration<T>實現的一部分:

public static class DbContextExtensions
{
    public static void ApplyHypertables(this Context context)
    {
        var entityTypes = context.Model.GetEntityTypes();

        foreach (var entityType in entityTypes)
        {
            foreach (var property in entityType.GetProperties())
            {
                var isHypertableColumn = property.FindAnnotation(MyAnnotationNames.Hypertable)?.Value;
                if ((bool)(isHypertableColumn ?? false))
                {
                    var tableName = entityType.GetTableName();
                    var columnName = property.GetColumnName();

                    context.Database.ExecuteSqlInterpolated(
                        $"SELECT create_hypertable({tableName}, {columnName});");
                }
            }
        }
    }
}

public static class MyAnnotationNames
{
    public const string Prefix = "MyPrefix:";
    public const string Hypertable = Prefix + "Hypertable";
}

public class IceCream
{
    public int IceCreamId { get; set; }
    public string Name { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

public class IceCreamConfiguration : IEntityTypeConfiguration<IceCream>
{
    public void Configure(EntityTypeBuilder<IceCream> builder)
    {
        builder.Property(e => e.UpdatedAt)
            .HasAnnotation(MyAnnotationNames.Hypertable, true);
        
        builder.HasData(
            new IceCream {IceCreamId = 1, Name = "Vanilla"},
            new IceCream {IceCreamId = 2, Name = "Chocolate"});
    }
}

public class Context : DbContext
{
    public DbSet<IceCream> IceCreams { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
        => modelBuilder.ApplyConfiguration(new IceCreamConfiguration());

    /// ...
}

internal static class Program
{
    private static void Main()
    {
        using var context = new Context();

        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();
        context.ApplyHypertables();

        var iceCreams = context.IceCreams
            .OrderBy(i => i.IceCreamId)
            .ToList();
        
        Debug.Assert(iceCreams.Count == 2);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM