[英]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.