52

That simple. I need to create a View using Code First. I found nothing about this on google nor SO. Is there a way to accomplish this?

I need that view to be created and queried using linq, so it's not a solution to create it using an script on Database creation, for example:

var results = from c in db.Customer
join v in db.MyView on c.Id equals v.Id
select c;

A work around is also acceptable. I need a way to query entities against non-constant/ non-entities values.

Chuck Norris
  • 963
  • 1
  • 9
  • 17

5 Answers5

91

you must manually create the view, just like AnatoliiG stated. (Adding index to a table).

You add the name of the view as an attribute to your class

[Table("UserDTO")]
    public class UserDTO
{
    /* Class code here */
}

You can create an empty migration by specifying the -IgnoreChanges attribute at the end

Add-Migration MigrationName -IgnoreChanges

This gives you an empty migration script that you can manually modify.

You can use your db context to execute your code in your migration script

public partial class editUserDTO : DbMigration
{
    public override void Up()
    {
        string script =
        @"
        CREATE VIEW dbo.UserDTO
        AS SELECT p.PersonId AS UserId, p.FirstName, p.LastName, u.UserName
        FROM dbo.Users u
        INNER JOIN dbo.People p ON u.PersonId = p.PersonId";
        BloggingContext ctx = new BloggingContext();
        ctx.Database.ExecuteSqlCommand(script);
    }

    public override void Down()
    {
        BloggingContext ctx = new BloggingContext();
        ctx.Database.ExecuteSqlCommand("DROP VIEW dbo.UserDTO");
    }
}
Community
  • 1
  • 1
Fred
  • 1,344
  • 1
  • 11
  • 16
  • 12
    Shouldn't the `CREATE` only should be in `Up()` and the `DROP` only be in the `Down()`? – Stafford Williams Aug 31 '15 at 03:01
  • hi there... Attempted to correct the code I wrote in this post, (removed ctx.Database.ExecuteSqlCommand(script); from the "Down" method) but was rejected by 3 users. – Fred Jun 20 '16 at 14:46
  • how to map my existing sql server to EF code first ? looking for good example. thanks – Monojit Sarkar Sep 09 '16 at 11:56
  • I did this and I get an error "Unable to update database to match the current model because there are pending changes and automatic migration is disabled." How do you resolve this? – Jim Kiely Sep 21 '16 at 21:01
  • 17
    Instead of creating a context and calling `ctx.Database.ExecuteSqlCommand`, you can just use the `Sql(...)` function inherited from `DbMigration`. – Rudey Aug 02 '17 at 07:54
  • 5
    Won't the changes ignored by `-IgnoreChanges` show up in the next added migration? – Rudey Aug 02 '17 at 07:55
  • 1
    Maybe missings steps, but I had to add Dbset of the new view class to the DbContext before the "Add-Migration" step. Also, after editing the empty migration script to implement the add and drop of the view, I had to drop the view manually and the run "Update-Database" to make sure I didn't make a mistake in the script and to complete the migration/database-update pair. – uonchiu Nov 16 '17 at 13:56
22

Just a heads up, in EF 6.1 (not sure if in earlier or not) there is now a Code First from Database option you can use and it will map to views as well.

I personally have mine in a separate junk project so I can just take out the code I want from it and not impact my project that actually uses the database. To use it Add a New file to your project -> Data -> ADO.NET Entity Data Model

Then select the Code First From Database option and select your views (and other tables if you want)

It will create it as a Table mapping like Fred was talking about in his answer, but will do all the code for you which is nice. You'll probably want to change the indexes and ordering though.

Then just call Sql(@"YOUR VIEW CREATE SQL HERE") in your Up and add a Sql(@"DROP STATEMENT HERE") in your Down

John
  • 6,503
  • 3
  • 37
  • 58
21

A lot of good insights from the official issues thread of EF7:

1) Don't have a DbSet, and instead have a property or extension method

A) Property

class YourContext
{
    public IQueryable<YourView> YourView 
    {
        get
        {
            return this.Database.SqlQuery<YourView>("select * from dbo.YourView");
        }
    }
}

B) Extension Method

static class YourContextExtensions
{
    public static IQueryable<YourView>(this YourContext context)
    {
        return context.Database.SqlQuery<YourView>("select * from dbo.YourView");
    }

2) Apparently, you can have the migration process ignore certain dbsets

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
  if (IsMigration)
    modelBuilder.Ignore<YourViewTable>();
 ...
}

(All the above are untested)

Kind Contributor
  • 17,547
  • 6
  • 53
  • 70
  • 1
    A point doesn't work `Cannot implicitly convert type 'Syste.Data.Entity.Infrastructure.DbRawSqlQuery .. to ...` you must change IQueryable to IEnumerable – Max Mar 30 '17 at 10:33
  • 1
    Tack, asqueryable to the end after sqlquery function – Kind Contributor Mar 30 '17 at 10:36
  • 3
    No, don't chain `AsQueryable` after `SqlQuery`. That won't provide you with a dynamic query object. When using `SqlQuery` as suggested, all records will be selected and loaded into memory, even though the code filters them with a `Where` or uses `FirstOrDefault`... See [this answer](https://stackoverflow.com/a/28664167/1185136). – Rudey Aug 02 '17 at 08:09
  • Solution number 2 tested and working here. I have used https://stackoverflow.com/a/31102959/1291428 as an inspiration for setting the isMigration flag. – Sebas Sep 06 '17 at 11:57
  • @Todd B cannot compile, where did you manage to get "this" in a static class without being in the method signature? =] – Natalie Perret Oct 27 '17 at 19:43
  • @Ethouarn fixed – Kind Contributor Oct 27 '17 at 22:34
12

You cannot create views with EF Code First approach. If you want to create view then execute creation sql script in Seed method. But you'll still not be able to map entity to this view, except hacking model by creating and droping table with same name as your view will have.

Some helpful links:

Community
  • 1
  • 1
Anatolii Gabuza
  • 6,184
  • 2
  • 36
  • 54
-5

You cannot create a view from EF Code First ,you should add the script in the 'seed' script to pre populate the view .

Debasis
  • 9
  • 1
  • 2
    Hi! Please revise your answer as it doesn't actually answer the OP's question but instead just indicates that what the OP wants to do can't be done. If you need help, check out [how to answer](https://stackoverflow.com/help/how-to-answer) in the help section. – Ortund May 23 '17 at 12:05
  • 1
    I don't think this belongs in the seed method. Creating a view should be done in an EF migration. – Rudey Aug 02 '17 at 07:56
  • 1
    This answer is the same as [this one from four years previous](https://stackoverflow.com/a/13594252/215552). – Heretic Monkey Nov 27 '18 at 22:01