在Entity Framework Core中使用SQL视图

时间:2016-03-15 13:24:31

标签: c# entity-framework entity-framework-core

例如,我有这样的模型:

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
} 

我想返回 ImageView 视图网址图片

我需要在哪里创建和定义SQL视图?

7 个答案:

答案 0 :(得分:31)

Entity Framework Core 2.1 中,我们可以按照Yuriy N的建议使用Query Types

有关如何使用它们的更详细的文章,请参见here

根据本文示例,最直接的方法是:

1。例如,我们有以下用于管理出版物的实体模型

public class Magazine
{
  public int MagazineId { get; set; }
  public string Name { get; set; }
  public string Publisher { get; set; }
  public List<Article> Articles { get; set; }
}

public class Article
{
  public int ArticleId { get; set; }
  public string Title { get; set; }
  public int MagazineId { get; set; }
  public DateTime PublishDate { get;  set; }
  public Author Author { get; set; }
  public int AuthorId { get; set; }
}
public class Author
{
  public int AuthorId { get; set; }
  public string Name { get; set; }
  public List<Article> Articles { get; set; }
}

2。我们有一个称为AuthorArticleCounts的视图,该视图定义为返回作者撰写的文章的名称和数量

SELECT
  a.AuthorName,
  Count(r.ArticleId) as ArticleCount
from Authors a
  JOIN Articles r on r.AuthorId = a.AuthorId
GROUP BY a.AuthorName

3。我们去创建一个用于View的模型

public class AuthorArticleCount
{
  public string AuthorName { get; private set; }
  public int ArticleCount { get; private set; }
}

4。之后,我们在DbContext中创建一个DbQuery属性,以使用模型内的视图结果

public DbQuery<AuthorArticleCount> AuthorArticleCounts{get;set;}

5。最后,我们可以轻松地获得View的结果。

var results=_context.AuthorArticleCounts.ToList();

答案 1 :(得分:22)

Entity Framework Core目前不支持视图。请参阅https://github.com/aspnet/EntityFramework/issues/827

也就是说,您可以通过将实体映射到视图来欺骗EF使用视图,就好像它是一个表一样。这种方法有局限性。例如如果您无法使用迁移,则需要手动为我们指定EF密钥,某些查询可能无法正常运行。要绕过最后一部分,您可以手动编写SQL查询

context.Images.FromSql("SELECT * FROM dbo.ImageView")

答案 2 :(得分:13)

这是在EF Core中使用SQL视图的新方法:Query Types

答案 3 :(得分:10)

EF Core不会在上下文calss中自动为SQL视图创建DBset,我们可以手动添加它们,如下所示。

public partial class LocalDBContext : DbContext
{ 

    public LocalDBContext(DbContextOptions<LocalDBContext> options) : base(options)
    {

    }

    public virtual DbSet<YourView> YourView { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<YourView>(entity => {
            entity.HasKey(e => e.ID);
            entity.ToTable("YourView");
            entity.Property(e => e.Name).HasMaxLength(50);
        });
    }

}

示例视图定义如下,几乎没有属性

using System;
using System.Collections.Generic;

namespace Project.Entities
{
    public partial class YourView
    {
        public string Name { get; set; }
        public int ID { get; set; }
    }
}

在上下文类中为视图和数据库集添加类后,最好通过控制器中的上下文对象使用视图对象。

答案 4 :(得分:6)

EF Core支持视图,here是详细信息。

此功能已在EF Core 2.1中的查询类型名称下添加。在EF Core 3.0中,该概念已重命名为无密钥实体类型。 [无密钥]数据注释在EFCore 5.0中可用。

它的工作方式与普通实体没有太大不同;但有一些特别之处。根据文档:

  • 无法定义键。
  • 从不跟踪DbContext中的更改,因此从不插入,更新或删除数据库。
  • 从未被惯例发现。
  • 仅支持导航映射功能的子集,具体来说:
  • 他们可能永远不会成为恋爱关系的主要目的。
  • 他们可能没有到拥有实体的导航
  • 它们只能包含指向常规实体的参考导航属性。
  • 实体不能包含无键实体类型的导航属性。
  • 需要配置[无键]数据注释或.HasNoKey()方法调用。
  • 可以映射到定义查询。定义查询是在模型中声明的查询,该查询充当无键实体类型的数据源

它的工作方式如下:

public class Blog
{
   public int BlogId { get; set; }
   public string Name { get; set; }
   public string Url { get; set; }
   public ICollection<Post> Posts { get; set; }
}

public class Post
{
   public int PostId { get; set; }
   public string Title { get; set; }
   public string Content { get; set; }
   public int BlogId { get; set; }
}

如果数据库中没有现有的View,则应按以下方式创建:

db.Database.ExecuteSqlRaw(
@"CREATE VIEW View_BlogPostCounts AS 
    SELECT b.Name, Count(p.PostId) as PostCount 
    FROM Blogs b
    JOIN Posts p on p.BlogId = b.BlogId
    GROUP BY b.Name");

然后,您应该拥有一个类来保存数据库视图中的结果:

  public class BlogPostsCount
  {
     public string BlogName { get; set; }
     public int PostCount { get; set; }
  }

并使用HasNoKey在OnModelCreating中配置无密钥实体类型:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      modelBuilder
          .Entity<BlogPostsCount>(eb =>
          {
             eb.HasNoKey();
             eb.ToView("View_BlogPostCounts");
             eb.Property(v => v.BlogName).HasColumnName("Name");
          });
    }

只需配置DbContext使其包含DbSet:

public DbSet<BlogPostsCount> BlogPostCounts { get; set; }

答案 5 :(得分:1)

QueryTypes是EF Core 2.1的规范答案,但是从数据库优先方法迁移(视图已经在数据库中创建)时,还有另一种使用方式:

  • 定义模型以匹配视图列(将模型类名称与视图名称匹配或使用Table属性。确保[Key]属性应用于至少一列,否则数据获取将失败
  • 在您的上下文中添加DbSet
  • 添加迁移(添加迁移)
  • 删除或注释掉用于基于提供的模型创建/删除“表”的代码
  • 更新数据库(更新数据库)

答案 6 :(得分:0)

可以构建视图。只需像搭建表一样使用 -Tables,只使用视图的名称。例如,如果您的视图名称是“vw_inventory”,则在包管理器控制台中运行此命令(将您自己的信息替换为“我的...”):

PM> Scaffold-DbContext "Server=MyServer;Database=MyDatabase;user id=MyUserId;password=MyPassword" Microsoft.EntityFrameworkCore.SqlServer -OutputDir Temp -Tables vw_inventory

此命令将在项目的 Temp 目录中创建模型文件和上下文文件。您可以将模型文件移动到您的模型目录中(记得更改命名空间名称)。您可以从上下文文件中复制您需要的内容并将其粘贴到项目中相应的现有上下文文件中。

注意:如果您想在使用本地数据库的集成测试中使用您的视图,您需要创建视图作为数据库设置的一部分。如果您要在多个测试中使用该视图,请确保添加该视图是否存在的检查。在这种情况下,由于 SQL“创建视图”语句需要是批处理中的唯一语句,因此您需要在存在检查语句中将创建视图作为动态 Sql 运行。或者,您可以单独运行“if exists drop view...”,然后运行“create view”语句,但如果多个测试同时运行,您不希望在另一个测试正在使用视图时删除该视图。 示例:

  void setupDb() {
    ...
    SomeDb.Command(db => db.Database.ExecuteSqlRaw(CreateInventoryView()));
    ...
  }
  public string CreateInventoryView() => @"
  IF OBJECT_ID('[dbo].[vw_inventory]') IS NULL
    BEGIN EXEC('CREATE VIEW [dbo].[vw_inventory] AS
       SELECT ...')
    END";