问题
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");
}
}
回答1:
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.
- Create a POCO class for the view; for example
FooView - Add the
DbSetproperty in theDbContextclass Use a
FooViewConfigurationfile to set a different name for the view (usingToTable("Foo"); in the constructor) or to set particular propertiespublic class FooViewConfiguration : EntityTypeConfiguration<FooView> { public FooViewConfiguration() { this.HasKey(t => t.Id); this.ToTable("myView"); }}
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 ()); }According to the above configuration,now your table is
this.ToTable("myView");.In other wordsmyView.Here is the
EF queryto retrieveall the dataon themyViewtable.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();
回答2:
Configure view as table and use this custom generator to prevent migration generation for tables marked as views
public class SkipViewGeneration : 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<AVMSDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
CodeGenerator = new SkipViewGeneration();
}
protected override void Seed(AVMSDbContext context)
{
// 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
来源:https://stackoverflow.com/questions/39411531/how-to-map-exisiting-sql-server-view-with-ef-code-first