6

i am fairly new in EF and learning EF code first. i am looking for a knowledge to map exisiting sql server view with EF code first. i have map my view with POCO but getting the below error.

when i try to fetch data from view then got the below error thrown

Additional information: The model backing the 'TestDBContext' context has changed since the database was created. Consider using Code First Migrations to update the database

my full code as follow

public class TestDBContext : DbContext
    {
        public TestDBContext()
            : base("name=TestDBContext")
        {
        }

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

        public DbSet<vwCustomer> vwCustomer { get; set; }
    }

public class vwCustomerConfiguration : EntityTypeConfiguration<vwCustomer>
{
    public vwCustomerConfiguration()
    {
        this.HasKey(t => t.CustomerID);
        this.ToTable("vwCustomer");
    }
}

      public class vwCustomer
        {
            public int CustomerID { get; set; }
            public string FirstName { get; set; }

        }

this way i am trying to load data.

    using (var db = new TestDBContext())
    {
        var listMyViews = db.vwCustomer.ToList();
    }

guide me what i am missing in code for which error is throwing. thanks

UPDATE1

When i issue Add-Migration "My_vwCustomer" then i saw new migration code added as below one. it seems there is no migration is pending.

   public partial class My_vwCustomer : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.vwCustomers",
                c => new
                    {
                        CustomerID = c.Int(nullable: false, identity: true),
                        FirstName = c.String(),
                    })
                .PrimaryKey(t => t.CustomerID);

        }

        public override void Down()
        {
            DropTable("dbo.vwCustomers");
        }
    }
Monojit Sarkar
  • 2,353
  • 8
  • 43
  • 94
  • I solved migration generation problem. [See my answer](https://stackoverflow.com/a/62287959/5200896) – giokoguashvili Jun 09 '20 at 17:01
  • To prevent migration from being added for your view you can use `.ToView()` instead of `.ToTable()` within the DbContext, change `this.ToTable("vwCustomer");` to `this.ToView("vwCustomer");` in your code – Nerdroid Feb 15 '21 at 03:41

2 Answers2

10

OP's Feedback :

When i generate the view with ADO.Net Entity model wizard then everything works fine.

You can do it as shown below.

Note : I have picked the 1 to 4 from this post.

  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 ovveriding the OnModelCreating method of the Context:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new FooViewConfiguration ());
    }
    
  5. According to the above configuration,now your table is this.ToTable("myView");.In other words myView.

    Here is the EF query to retrieve all the data on the myView table.

    var listMyViews = yourDbContext.myView.ToList()

Your projection may be like this :

var query = yourDbContext.myView
        .Select(v=> new
        {
            ID = v.ID,
            EmpName = v.EmpName,
            Salary = v.Salary 
        }).ToList();
Community
  • 1
  • 1
Sampath
  • 63,341
  • 64
  • 307
  • 441
2

Configure view as a table and use this custom generator to prevent migration generation for tables marked as views

public class SkipViewGenerator: CSharpMigrationCodeGenerator
{
    protected override void Generate(CreateTableOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(RenameTableOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(MoveTableOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(DropTableOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(AddColumnOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Table))
            base.Generate(operation, writer);
    }

    protected override void Generate(DropColumnOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Table))
            base.Generate(operation, writer);
    }

    protected override void Generate(DropPrimaryKeyOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Table))
            base.Generate(operation, writer);
    }

    protected override void Generate(AlterColumnOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Table))
            base.Generate(operation, writer);
    }

    protected override void Generate(AddPrimaryKeyOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Table))
            base.Generate(operation, writer);
    }

    protected override void Generate(AlterTableOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(CreateIndexOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    protected override void Generate(DropIndexOperation operation, IndentedTextWriter writer)
    {
        if (!IsView(operation.Name))
            base.Generate(operation, writer);
    }

    private bool IsView(string tableNameWithSchemaName)
    {
        var tableName = DatabaseName.Parse(tableNameWithSchemaName).Name;
        var schemaName = DatabaseName.Parse(tableNameWithSchemaName).Schema;
        return schemaName.Contains("View");
    }
}

Usage example

internal sealed class Configuration : DbMigrationsConfiguration<MyDbContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
        CodeGenerator = new SkipViewGenerator();
    }

    protected override void Seed(MyDbContextcontext)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method
        //  to avoid creating duplicate seed data.
    }
}

DatabaseName.Parse implementatnion you can get from Github sources

giokoguashvili
  • 2,013
  • 3
  • 18
  • 37