如何在Code First Entity Framework中使用视图

102

我该如何在Entity Framework Code First中使用数据库视图?


3
以下答案都没有解释如何使用EF migrations创建视图。请参考这个答案中的类似问题。 - Rudey
这里有一个完全相同问题的线程。 -https://dev59.com/yWYr5IYBdhLWcg3wi6vd?noredirect=1&lq=1- - Mantra
请尝试我的解决方案。它可以防止将标记为视图的表生成迁移。 - giokoguashvili
4个回答

104

如果你和我一样,只对将来自其他数据库(例如ERP)的实体映射到你的应用程序特定实体感兴趣,那么你可以像使用表格一样使用视图(以相同方式映射视图!)。当然,如果你尝试更新这些实体,如果视图不可更新,则会出现异常。

  1. Create a POCO class for the view; for example FooView

  2. Add the DbSet property in the DbContext class

  3. Use a FooViewConfiguration file to set a different name for the view (using ToTable("Foo"); in the constructor) or to set particular properties

    public class FooViewConfiguration : EntityTypeConfiguration<FooView>      
    {
        public FooViewConfiguration()
        {
            this.HasKey(t => t.Id);
            this.ToTable("myView");
        }
    }
    
  4. Add the FooViewConfiguration file to the modelBuilder, for example overriding the OnModelCreating method of the Context:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooViewConfiguration ());
    }
    

71
请将文本从英语翻译成中文。仅返回翻译后的文本:+1,不要假设“Code First”==自动生成数据库。 - onetwopunch
3
你的意思是创建一个类似于其他实体的视图类,比如命名为 FooView,并在我的 DbContext 类中添加一个 DbSet<FooView> 属性,然后 Entity Framework 就知道将其映射到视图上(假设我们有一个名为 dbo.Foo 的视图)? - Ashkan
23
只有我这样,还是每个人在迁移时都会创建空表?有没有办法避免这种情况发生? - Kremena Lalova
4
请确认一下,这个解决方案是否要求我们事先在 SQL 数据库上创建视图?是否可以在代码中定义视图,并通过 Add-Migration/Update-Database 命令将其填充到数据库中? - frostshoxx
8
几个事情。1. 这个答案没有提到你必须手动使用SQL创建视图,可以使用迁移完成这一步骤。2. 如果类名和视图名相同,则无需配置视图名称。3. 您可以像这样使用DataAnnotations:[Table("myView")],这可能比使用 EntityTypeConfiguration 更简单。 - Rudey
显示剩余12条评论

37

这可能是一个更新提示,但要在EF Code First中使用视图,只需将 [Table("NameOfView")] 添加到类的顶部,一切都应该正常工作,无需像其他人一样经历所有麻烦。另外,您需要将其中一个列报告为[key]列。以下是我实现它的示例代码。

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace SomeProject.Data
{
    [Table("SomeView")]
    public class SomeView
    {
        [Key]
        public int NameID { get; set; }
        public string Name { get; set; }
    }
}

这是上下文的样子

using System.Data.Entity;

namespace SomeProject.Data
{
    public class DatabaseContext : DbContext
    {
        public DbSet<SomeView> SomeViews { get; set; }
    }
}

2
这与被接受的答案相同,只是这里使用了DataAnnotations,而被接受的答案使用了EF Fluid API。 - Rudey
5
实际上不是这样的。我尝试过接受的答案,但没有成功,对我来说效果不佳。不过我的情况中使用了迁移,这可能影响了一些东西。我发现必须先进行迁移,然后再添加视图类,因为它已经存在于数据库中。如果我们已经有现有的表格,我们会以完全相同的方式处理。由于视图是"虚拟表",所以在Entity Framework中仍然可以使用表格语法。 - Charles Owen

14

如果您只想要一堆非规范化的对象,那么您可以在您的DbContext类中创建一个公共的只读IQueryable<TDenormolized>属性。

get中,您返回一个Linq结果,将非规范化值投影到非规范化对象中。这可能比编写DB View更好,因为您在编程,不仅限于使用select语句。此外,它是编译时类型安全的。

只需小心不要触发枚举,如ToList()调用,这将打破延迟查询,您可能会从数据库获取100万条记录并在应用程序服务器上过滤它们。

我不知道这是否是正确的方法,但我尝试过,并且对我有效。


6
我希望你能够翻译以下内容:使用视图的原因之一是,EF 生成的 SQL 不总是“好的”——我们的模型中有一些继承层次结构(发现问题太晚了……),使用视图可以让我们手动创建 SQL。这是一个反对意见,说明为什么使用视图会更可取。 - Carl
2
另一个不这样做的原因可能是使用递归公共表达式,在LINQ中不可用。但对于更简单的情况,这是一个很好的建议。 - Tom Pažourek
2
如果你想利用索引视图的好处,使用属性而不是视图不是一个选项。 - Rudey
你不仅仅局限于使用SELECT语句。这是什么意思?LINQ可以做的任何事情都可以使用SELECT语句完成,但反过来则不一定成立。 - Rudey

4
我知道这是一个老问题,这里有很多答案。但当我使用这个答案时,我遇到了一个问题,当我在Package Manager控制台中使用update-database命令时出现了错误:

数据库中已经存在名为'...'的对象。

我用以下步骤解决了这个问题:
  1. 在Package Manager控制台中运行此命令:Add-migration intial
  2. 在迁移文件夹下,你可以找到..._intial.cs文件,打开它并注释或删除与你想映射的类相关的任何命令
  3. 现在你可以正常地对模型进行任何其他更改的update-database命令
希望能对您有所帮助。

1
谢谢!这真的很有帮助!作为额外的提示,您不仅可以删除使用EF Migrations生成的代码,还可以添加'migrationBuilder.Sql("CREATE OR REPLACE VIEW ...")',以便同事也可以使用它来升级他们的数据库。 - Rich_Rich
这只是一种替代方法,是否有任何方法可以将类从迁移过程中排除?就像 DataAnnotations 中的 NotMapped 一样。 - Ariwibawa
在你的 OnModelCreating 中添加 if (IsMigration) modelBuilder.Ignore<ViewEntityName>(); - mBardos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接