table 创建后的 EFCore EnsureCreated() 运行 命令
EFCore EnsureCreated() run command after table creation
所以我是 EFCore 的新手(直接进入 5.0 预览版,因为为什么不),并且享受所有流畅的配置方面。整个 IEntityTypeConfiguration<>
概念确实有助于使实体对支持数据库不可知(而不是在实体本身上使用属性)。
我在 Startup.cs 中使用 DbContext.Database.EnsureCreated()
生成整个数据库。当我在玩的时候,它目前由 SQLite 支持,但我想最终转移到带有 TimescaleDB 扩展的 PostgreSQL。
问题是,在使用 TimescaleDB 时,我需要在创建 table 本身后立即发出 create_hypertable()
。
table 创建后发出命令的最佳方式是什么?
- 在
EnsureCreated()
之后,使用 ExecuteSqlRaw()
?这意味着 all table 已在执行 SQL 之前创建。我希望它尽可能接近 table 创作。
DbContext
里面的某个地方?
- 在我的
IEntityTypeConfiguration<>
?
- 或其他地方?
谢谢!
如果您想继续使用 context.Database.EnsureCreated()
,那么 运行 您自己的脚本(例如,通过执行 context.Database.ExecuteSqlRaw()
)是在调用之后的方法。
That means all the tables have been created before the SQL is executed. I would prefer having it as close to the table creation as possible.
据我所知,这应该没有任何缺点,因此通过将 create_hypertable()
调用靠近另一个 table 不会获得任何好处(如果您不同意,请详细说明为什么会这样)。
如果您真的 出于某种原因想要将调用移动到另一个命令附近,那么您可以实施 DbCommandInterceptor
。然后您可以解析特定 CREATE TABLE
语句或其他内容的命令文本,然后发出您自己的语句。 (如果你想走那条路,post 发表评论,我会用一些代码更新这个答案。)
如果您从使用 context.Database.EnsureCreated()
切换到迁移,您可以使用 Sql()
方法来注入您自己的语句:
public partial class MyMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("SELECT create_hypertable('conditions', 'time');")
}
}
也许你可以详细说明一下,为什么你觉得有必要将 create_hypertable()
调用更接近他们的 table。
如果您只关心在 C# 代码中关闭 create_hypertable()
调用,但不一定在生成的 SQL 代码中关闭,则引入自定义属性(或接口)和方法将 hypertable 应用于所有具有用此属性装饰的属性(或实现此接口)的实体可能就足够了:
[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);
}
}
如果您想保持模型 类 没有任何特定于数据库的属性,您可以改用注释。想法基本相同,但注释是 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);
}
}
所以我是 EFCore 的新手(直接进入 5.0 预览版,因为为什么不),并且享受所有流畅的配置方面。整个 IEntityTypeConfiguration<>
概念确实有助于使实体对支持数据库不可知(而不是在实体本身上使用属性)。
我在 Startup.cs 中使用 DbContext.Database.EnsureCreated()
生成整个数据库。当我在玩的时候,它目前由 SQLite 支持,但我想最终转移到带有 TimescaleDB 扩展的 PostgreSQL。
问题是,在使用 TimescaleDB 时,我需要在创建 table 本身后立即发出 create_hypertable()
。
table 创建后发出命令的最佳方式是什么?
- 在
EnsureCreated()
之后,使用ExecuteSqlRaw()
?这意味着 all table 已在执行 SQL 之前创建。我希望它尽可能接近 table 创作。 DbContext
里面的某个地方?- 在我的
IEntityTypeConfiguration<>
? - 或其他地方?
谢谢!
如果您想继续使用 context.Database.EnsureCreated()
,那么 运行 您自己的脚本(例如,通过执行 context.Database.ExecuteSqlRaw()
)是在调用之后的方法。
That means all the tables have been created before the SQL is executed. I would prefer having it as close to the table creation as possible.
据我所知,这应该没有任何缺点,因此通过将 create_hypertable()
调用靠近另一个 table 不会获得任何好处(如果您不同意,请详细说明为什么会这样)。
如果您真的 出于某种原因想要将调用移动到另一个命令附近,那么您可以实施 DbCommandInterceptor
。然后您可以解析特定 CREATE TABLE
语句或其他内容的命令文本,然后发出您自己的语句。 (如果你想走那条路,post 发表评论,我会用一些代码更新这个答案。)
如果您从使用 context.Database.EnsureCreated()
切换到迁移,您可以使用 Sql()
方法来注入您自己的语句:
public partial class MyMigration : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("SELECT create_hypertable('conditions', 'time');")
}
}
也许你可以详细说明一下,为什么你觉得有必要将 create_hypertable()
调用更接近他们的 table。
如果您只关心在 C# 代码中关闭 create_hypertable()
调用,但不一定在生成的 SQL 代码中关闭,则引入自定义属性(或接口)和方法将 hypertable 应用于所有具有用此属性装饰的属性(或实现此接口)的实体可能就足够了:
[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);
}
}
如果您想保持模型 类 没有任何特定于数据库的属性,您可以改用注释。想法基本相同,但注释是 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);
}
}