【问题标题】:Create Database Views using EF Core Code First approach使用 EF Core 代码优先方法创建数据库视图
【发布时间】:2019-11-04 13:00:04
【问题描述】:

我正在开发一个需要创建数据库视图的新应用程序。我正在使用具有 MySql 风格的 EF 核心,并使用 Code First 方法来创建数据库和表。虽然我没有找到创建视图的方法。如果不知何故,我可以在迁移步骤中执行原始 sql,这可能有助于创建视图并稍后将其映射为 DbSet。我无法手动创建视图,因为它需要针对数据库执行视图脚本,而这在更高的环境中是不可能的。有人可以指导我。非常感谢您的帮助!

【问题讨论】:

  • migrationBuilder.Sql(raw_sql);

标签: entity-framework entity-framework-core


【解决方案1】:

据我所知,您无法直接使用 EF Core 创建视图。但是,您可以在升级时使用迁移来执行任意 SQL。

  1. 在包管理器控制台中生成一个迁移,即使没有什么可做的:add-migration CreatingTheView
  2. 打开生成的迁移类,文件名:Migrations\yyyyMMdd_CreatingTheView.cs
  3. 通过修改Up方法添加要在升级时执行的原始SQL:migrationBuilder.Sql("CREATE VIEW etc.");
  4. 如果要支持降级,修改Down方法:migrationBuilder.Sql("DROP VIEW etc.");

【讨论】:

    【解决方案2】:

    既然您使用的是 Code First,那么数据库可能只是应用程序的扩展,而不是它自己的主要目标?在这种情况下,您可能真的不需要视图。

    数据库不会关心您是否只发送普通查询,并且您可以在应用程序层中将它们抽象化。最基本的技巧是在您的DbContext 实现(或扩展方法)中创建一个IQueryable<T> 属性,它会查询您希望显示的数据。像这样的:

    public sealed class DatabaseContext : DbContext
    {
        public DbSet<Transaction> Transactions { get; set; }
    
        public IQueryable<PerPersonSum> PerPersonSums
            => Transactions.GroupBy(t => t.Person,
                                    (k, g) => new PerPersonSum
                                    {
                                        Person = k,
                                        TotalAmount = g.Sum(t => t.Amount)
                                    });
    }
    

    更合适的解决方案是keyless entity type:

    public sealed class DatabaseContext : DbContext
    {
        public DbSet<Transaction> Transactions { get; set; }
    
        public DbSet<PerPersonSum> PerPersonSums { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<PerPersonSum>(e =>
            {
                e.HasNoKey();
                e.ToQuery(() => Transactions.GroupBy(t => t.Person,
                                                     (k, g) => new PerPersonSum
                                                     {
                                                         Person = k,
                                                         TotalAmount = g.Sum(t => t.Amount)
                                                     }));
            });
        }
    }
    

    在 3.0 之前,它曾经被称为查询类型,可以这样使用:

    public sealed class DatabaseContext : DbContext
    {
        public DbSet<Transaction> Transactions { get; set; }
    
        public DbQuery<PerPersonSum> PerPersonSums { get; set; }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Query<PerPersonSum>()
                        .ToQuery(() => Transactions.GroupBy(t => t.Person,
                                                            (k, g) => new PerPersonSum
                                                            {
                                                                Person = k,
                                                                TotalAmount = g.Sum(t => t.Amount)
                                                            }));
        }
    }
    

    【讨论】:

    • 我真的很喜欢这个解决方案,感觉应该有人告诉我为什么这很糟糕,哈哈
    • @workabyte 取决于项目的目的。应用程序是项目的重点,并提供数据服务吗?还是数据是焦点,应用程序为数据提供服务?我通常有数据服务于应用程序,所以我几乎从不使用视图(这就是为什么我几乎总是使用 SQLite 而不是“真正的”RDBMS)。如果数据库是真正的产品并且预计比应用程序存在的时间更长,那么视图可能是首选。另一方面,在这种情况下,代码优先也可能是一个错误。
    • @relatively_random 一些数据库不会将视图视为已保存的查询,并且可以对其进行更多优化。这不应该也是一个考虑因素吗?
    • @InbarBarkai 听起来确实如此。不幸的是,我并不是数据库方面的专家,我的大部分经验来自 EFC 和 SQLite。这是基本上所有传统数据库引擎的标准功能吗? SQLite 实际上将视图视为复制粘贴到查询中的文本。至少我上次检查时确实如此。
    • @relatively_random 据我所知,Oracle 和 PostgreSQL 实际上正在对视图进行一些优化。也许 Microsoft SQL Server 也能做到这一点,但我已经有一段时间没有使用它了。
    【解决方案3】:

    relative_random 的答案几乎对我有用,但我必须使用这种语法才能让它工作:

    migrationBuilder.Sql(@"exec('create view dbo.MyViewName as ....');");
    

    migrationBuilder.Sql("exec('drop view dbo.MyViewName');");
    

    否则我得到一个 sql 错误“创建视图必须是批处理中唯一的语句”。

    【讨论】:

      猜你喜欢
      • 2019-10-23
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 1970-01-01
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多