102

How can I use the database view in entity framework code first,

HaveNoDisplayName
  • 8,291
  • 106
  • 37
  • 47
Sagar
  • 1,727
  • 4
  • 22
  • 30
  • 3
    None of the answers below explain how to create a view using EF migrations. See [this answer](https://stackoverflow.com/a/18707413/1185136) for a similar question. – Rudey Aug 02 '17 at 08:28
  • Here is a thread with exactly same question. -https://stackoverflow.com/questions/13593845/how-to-create-a-view-using-ef-code-first-poco?noredirect=1&lq=1- – Mantra Jan 22 '20 at 14:39
  • Try my [solution](https://stackoverflow.com/a/62287959/5200896). It prevents migration generation for tables marked as views – giokoguashvili Jun 09 '20 at 17:05

4 Answers4

103

If, like me, you are interested only in mapping entity coming from an other database (an erp in my case) to relate them to entities specific of your application, then you can use the views as you use a table (map the view in the same way!). Obviously, if you try to update that entities, you will get an exception if the view is not updatable. The procedure is the same as in the case of normal (based on a table) entities:

  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 ());
    }
    
Tim
  • 5,435
  • 7
  • 42
  • 62
Daniele Armanasco
  • 7,289
  • 9
  • 43
  • 55
  • 71
    +1 for not assuming that "Code First" == auto database generation – onetwopunch Jun 28 '12 at 18:26
  • 1
    Even if it's auto-gen, you can script the views in your IDatabaseInitializer and so long as your using an "class ViewName : Entity" that matches up like this answer is suggesting, you'll be fine. – Dave Jellison Jan 20 '13 at 22:38
  • 3
    @DaveJellison would you care to elaborate, or provide a link on adding a view as part of an IDatabaseInitializer – Ralph Shillington May 29 '13 at 11:32
  • 1
    @Ashkan There is no step by step solution in this answer because the answer is: you can use views in the same way you are using tables, provided that you don't need to update the data. I assumed that Sagar knows how to use tables with EF because this is not the object of the question. – Daniele Armanasco Jul 13 '13 at 15:50
  • 3
    You mean just create a class like other entities for the view, for example named `FooView` and add a `DbSet` property in my DbContext class, and entity framework knows to map it to the view (let's say we have a view named `dbo.Foo`) ?? – Ashkan Jul 13 '13 at 17:09
  • 2
    Yes, and you can use a FooViewConfiguration file to set a different name for the view (using ToTable("Foo"); in the constructor) or to set particular properties. All the same as if you were working with a table and not a view. – Daniele Armanasco Jul 13 '13 at 17:28
  • Here is your step by step solution :) – Ashkan Jul 13 '13 at 20:16
  • 1
    what happens if you do `modelBuilder.Entity().ToTable("VIEW_NAME");` ? – C. Tewalt May 19 '15 at 20:10
  • So what if you do not want to map a view to your EF model but you really need let say a materialized view for performance reasons? – Santhos Jun 24 '15 at 12:20
  • 23
    Is it just me, or everyone is getting empty table created by the migration? Is there a way to avoid that? – Kremena Lalova Jul 02 '15 at 16:05
  • 4
    Just making sure here, is this solution required us to create View on the SQL database beforehand externally? Is it possible to define view in the code and have it populate in the database through Add-Migration/Update-Database command? – frostshoxx Oct 15 '15 at 12:42
  • Where do I specify the foreign key on my table to the view? So I have a "Post" table that I need to join to "UserView". The Post table has a userID but in order for me to map Post table to the User View there needs to be a relationship and this answer does not tell me how to specify that relationship – MobileMon Sep 16 '16 at 14:10
  • Name of view in SQL cannot match POCO name, or migrations will delete your view, and replace it with a blank table. At least, I'm pretty sure that's what happened the first time I tried this. – samuelesque Oct 18 '16 at 17:31
  • 1
    https://msdn.microsoft.com/en-us/magazine/dn519921.aspx from Julie Lerman shows how to create a view in CF migrations – Phil Boyd Jan 18 '17 at 23:03
  • 8
    A few things. 1. This answer fails to mention you have to create the view manually using SQL, this can be done using a migration. 2. You don't have to configure the view name if the class name matches the view name. 3. You can use DataAnnotations like so: `[Table("myView")]`, this is arguably simpler than using creating a `EntityTypeConfiguration`. – Rudey Aug 02 '17 at 08:22
  • Kremena Lalova just comment CreateTable statement in migration configuration in method named Up – Zviadi Oct 05 '17 at 14:37
  • My view doesnt have ID column. It did not work for my issue – aj go Jan 25 '21 at 00:19
37

This may be an update but to use views with EF Code first simply add [Table("NameOfView")] to the top of the class and all should work right without having to go through all the hoops everyone else is going through. Also you will have to report one of the columns as a [key] column. Here is my sample code below to implement it.

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; }
    }
}

And here is what the context looks like

using System.Data.Entity;

namespace SomeProject.Data
{
    public class DatabaseContext : DbContext
    {
        public DbSet<SomeView> SomeViews { get; set; }
    }
}
Al Katawazi
  • 7,192
  • 6
  • 26
  • 39
  • 2
    This is the same as the accepted answer, except this uses DataAnnotations while the accepted answer uses the EF Fluid API. – Rudey Aug 02 '17 at 08:26
  • 5
    Actually no it isn't. I tried, without success, on the accepted answer and it didn't work well for me. But then I'm using Migrations so this may have impacted things. I found I had to do my migrations first THEN add my view class since it already existed in the database. We'd handle it exactly the same way if we already had existing tables in the database. Since a view is a "virtual table" the table syntax in the Entity Framework still works. – Charles Owen Mar 27 '18 at 20:39
14

If all you want is a bunch of de-normalized objects, then you might just created a public get-only IQueryable<TDenormolized> property in your DbContext class.

In the get you return a Linq result to project the de-normoalized values into your de-normalized objects. This might be better than writing a DB View because you are programming, you are not limited by only using select statements. Also it's compile time type safe.

Just be careful not trigger enumerations like ToList() calls, that will break the deferred query and you may end up with getting a million records back from the database and filter them on your application server.

I don't know if this is the right way, but I tried and it works for me.

imp25
  • 2,327
  • 16
  • 23
oldhouseye
  • 141
  • 1
  • 2
  • 6
    One of the reasons I'd like to use views is that the SQL generated by EF is not always 'nice' - we have some inheritance hierarchies in our model (found out about the pitfalls too late...) and using views allows us to manually create the SQL. Just a counterpoint as to why a view would be preferable – Carl Jul 17 '15 at 08:26
  • 2
    Other reason not to do this might be the usage of recursive common table expressions, which are not available in LINQ. But otherwise this is a good advice for simpler scenarios. – Tom Pažourek May 16 '16 at 13:48
  • 2
    Using a property instead of a view is not an option if you want to make use of the benefits of an *indexed* view. – Rudey Aug 02 '17 at 07:37
  • "you are not limited by only using select statements". What do you mean by this? Anything you can do with LINQ can be done using SELECT statements, the same can't be said for the other way around. – Rudey Aug 02 '17 at 08:24
4

I know this is an old question and there is many answers here, but I forced to an issue when I use this answer and an error occurred when I use update-database command in Package Manager Console:

There is already an object named '...' in the database.

and I use these steps to solve this issue:

  1. run this command in Package Manager Console:Add-migration intial
  2. Under the Migrations folder, you can find ..._intial.cs file, open it and comment or delete any command related to your class you want to map
  3. now you can normally use update-database command for any other change to your models

hope it helps.

Sepehr Estaki
  • 331
  • 5
  • 19
  • 1
    Thanks! This really helped! As an extra, instead of just removing code generated with EF Migrations, you can instead add there `migrationBuilder.Sql("CREATE OR REPLACE VIEW ...`); So that colleagues can also use it to upgrade their database. – Rich_Rich Oct 16 '19 at 19:57
  • This is just an alternatif, is there any method to exclude class from migration proses? Just like NotMapped in DataAnnotations for method. – Ariwibawa Jan 22 '21 at 05:47
  • In your `OnModelCreating` add `if (IsMigration) modelBuilder.Ignore();` Source: https://www.c-sharpcorner.com/article/how-to-implement-database-views-using-entity-framework-ef-code-first-approach/ – mBardos Oct 26 '21 at 13:42