请教个ef code first 外键DbContext问题

Entity Framework code first 手动修改数据库的问题 - 推酷
Entity Framework code first 手动修改数据库的问题
1. 手动给表格添加字段或者新增一个表格会不会对DBContext产生影响呢?
不会产生影响,如果我们不想code中的model不和数据库中增加的保持一致,可以不添加对应的字段和model,但是如果我们需要保持一致,如何做呢
步骤如下:
a. 将Model手动改成与数据库一致
b. 在执行DbContext的实例化前加一句 Database.SetInitializer&BloggingContext&(null);&
c. 如果以后你需要在添加model ,则如果你把之前你手动改动与数据库同步的部分注释掉,然后再利用add-update-database来更新仍然是可以用的
下面的例子展示了如何做:
手动在数据更改之前:
public class Blog
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public virtual List&Post& Posts { get; set; }
public class User
public int UserId { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
//public int? age { }
//public string interest { }
public class School
public int SchoolId { get; set; }
public string SchoolName { get; set; }
public int SchoolLevel { 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; }
public virtual Blog Blog { get; set; }
public class Tutorial
public int Id { get; set; }
public int Name { get; set; }
public class BloggingContext : DbContext
public DbSet&Blog& Blogs { get; set; }
public DbSet&Post& Posts { get; set; }
public DbSet&User& Users { get; set; }
public DbSet&Tutorial& Tutorials { get; set; }
//public DbSet&School& Schools { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity&User&().Property(u =& u.DisplayName).HasColumnName(&display_name&);
modelBuilder.Entity&User&().Property(u =& u.Username).HasColumnName(&user_name&);
数据库中的表:
手动添加了表Schools并且更改了Users表中的字段
自己手动更改Model并保持与数据库同步
public class Blog
public int BlogId { get; set; }
public string Name { get; set; }
public string Url { get; set; }
public virtual List&Post& Posts { get; set; }
public class User
public int UserId { get; set; }
public string Username { get; set; }
public string DisplayName { get; set; }
public int? age { get; set; }
public string interest { get; set; }
public class School
public int SchoolId { get; set; }
public string SchoolName { get; set; }
public int SchoolLevel { 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; }
public virtual Blog Blog { get; set; }
public class Tutorial
public int Id { get; set; }
public int Name { get; set; }
public class BloggingContext : DbContext
public DbSet&Blog& Blogs { get; set; }
public DbSet&Post& Posts { get; set; }
public DbSet&User& Users { get; set; }
public DbSet&Tutorial& Tutorials { get; set; }
public DbSet&School& Schools { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
modelBuilder.Entity&User&().Property(u =& u.DisplayName).HasColumnName(&display_name&);
modelBuilder.Entity&User&().Property(u =& u.Username).HasColumnName(&user_name&);
如果你调用add-migration and update-database 会提示
There is already an object named 'Schools' in the database.
所以你去访问数据库时会出现错误:
using (var db = new BloggingContext())
//var query2 = from b in db.Schools
orderby b.SchoolName
//var schoolList = query2.ToList();
var query1 = from b in db.Users
orderby b.Username
var userList = query1.ToList();
// Create and save a new Blog
Console.Write(&Enter a name for a new Blog: &);
var name = Console.ReadLine();
var user = new User { UserId = 0, Username = name };
db.Users.Add(user);
db.SaveChanges();
//var blog = new Blog { Name = name };
//db.Blogs.Add(blog);
//db.SaveChanges();
// Display all Blogs from the database
var query = from b in db.Blogs
orderby b.Name
Console.WriteLine(&All blogs in the database:&);
foreach (var item in query)
Console.WriteLine(item.Name);
Console.WriteLine(&Press any key to exit...&);
Console.ReadKey();
会产生异常:
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
Additional information: The model backing the 'BloggingContext' context has changed since the database was created. Consider using Code First Migrations to update the database (/fwlink/?LinkId=238269).
如果在using (var db = new BloggingContext())前加上Database.SetInitializer&BloggingContext&(null);就不会报错
但是如果以后想添加Model的话,怎么做呢,我们可以将之前你添加与手动添加School表和修改user表的一些信息注释掉,migration文件也删除,然后你在添加model再去执行数据迁移就不会出问题,迁移好了后,你在重新反注释即可。
2. 数据库连接字符串的更改
在 Code First 模式下按约定使用连接
如果您还没有在应用程序中进行任何其他配置,则对 DbContext 调用无参数构造函数将会导致 DbContext 使用按约定创建的数据库连接在 Code First 模式下运行。例如:
1 namespace Demo.EF
public class BloggingContext : DbContext
public BloggingContext()
// C# will call base class parameterless constructor by default
在此示例中,DbContext 使用派生上下文类 Demo.EF.BloggingContext 的命名空间限定名称作为数据库名称,并使用 SQL Express 或 LocalDb 为此数据库创建连接字符串。如果同时安装了这两个数据库,将使用 SQL Express。
默认情况下,Visual Studio 2010 包含 SQL Express,Visual Studio 2012 包含 LocalDb。安装期间,EntityFramework NuGet 包会检查哪个数据库服务器可用。随后 NuGet 包将设置按约定创建连接时 Code First 所使用的默认数据库服务器,以此更新配置文件。如果 SQL Express 正在运行,将使用它。如果 SQL Express 不可用,则 LocalDb 将注册为默认数据库。如果配置文件已包含默认连接工厂设置,则不会更改该文件。
在 Code First 模式下按约定和指定数据库名称使用连接
如果您尚未在应用程序中进行任何其他配置,在通过要使用的数据库名称对 DbContext 调用字符串构造函数时,将会导致 DbContext 使用按约定创建的与该名称数据库的连接在 Code First 模式下运行。例如:
public class BloggingContext : DbContext
public BloggingContext()
: base(&BloggingDatabase&)
在此示例中,DbContext 使用“BloggingDatabase”作为数据库名称,并使用 SQL Express(随 Visual Studio 2010 安装)或 LocalDb(随 Visual Studio 2012 安装)为此数据库创建连接字符串。如果同时安装了这两个数据库,将使用 SQL Express。
在 Code First 模式下使用 app.config/web.config 文件中的连接字符串
可以选择将连接字符串放入 app.config 或 web.config 文件中。例如:
&configuration&
&connectionStrings&
&add name=&BloggingCompactDatabase&
providerName=&System.Data.SqlServerCe.4.0&
connectionString=&Data Source=Blogging.sdf&/&
&/connectionStrings&
&/configuration&
这是一种指示 DbContext 使用数据库服务器而非 SQL Express 或 LocalDb 的简单方法 — 上例指定了 SQL Server Compact Edition 数据库。
如果连接字符串的名称与上下文的名称(带或不带命名空间限定)相同,则使用无参数构造函数时 DbContext 会找到该连接字符串。如果连接字符串名称与上下文名称不同,则可通过将连接字符串名称传递给 DbContext 构造函数,指示 DbContext 在 Code First 模式下使用此连接。例如:
1 public class BloggingContext : DbContext
public BloggingContext()
: base(&BloggingCompactDatabase&)
或者,也可以对传递给 DbContext 构造函数的字符串使用 “name=&连接字符串名称&”格式。例如:
1 public class BloggingContext : DbContext
public BloggingContext()
: base(&name=BloggingCompactDatabase&)
使用此形式可以明确要求在配置文件中查找连接字符串。如果未找到具有给定名称的连接字符串,则将引发异常。
Database/Model First 使用 app.config/web.config 文件中的连接字符串
使用 EF 设计器创建的模型不同于 Code First,因为该模型事先已存在,而不是在应用程序运行时从代码生成的。该模型通常在项目中以 EDMX 文件形式存在。
Designer 会将 EF 连接字符串添加到 app.config 或 web.config 文件中。此连接字符串十分特殊,因为它说明了如何在 EDMX 文件中查找信息。例如:
1 &configuration&
&connectionStrings&
&add name=&Northwind_Entities&
connectionString=&metadata=res://*/Northwind.csdl|
res://*/Northwind.ssdl|
res://*/Northwind.
provider=System.Data.SqlC
provider connection string=
&Data Source=.\
Initial Catalog=N
Integrated Security=T
MultipleActiveResultSets=True&&
providerName=&System.Data.EntityClient&/&
&/connectionStrings&
15 &/configuration&
EF 设计器还将生成一些代码,指示 DbContext 通过将连接字符串名称传递给 DbContext 构造函数来使用此连接。例如:
1 public class NorthwindContext : DbContext
public NorthwindContext()
: base(&name=Northwind_Entities&)
由于连接字符串是包含待用模型详细信息的 EF 连接字符串,因此 EF DbContext 十分清楚要加载现有模型(而不是使用 Code First 从代码计算模型)。
其他 DbContext 构造函数选项
DbContext 类包含支持其他一些更高级方案的其他构造函数和使用模式。其中一些选项有:
可以使用 DbModelBuilder 类构建 Code First 模型,而不实例化 DbContext 实例。这样会生成 DbModel 对象。随后,在准备好创建 DbContext 实例时,可以将此 DbModel 对象传递给某一 DbContext 构造函数。
可以将完整连接字符串传递给 DbContext,而不仅仅传递数据库或连接字符串名称。此连接字符串默认用于 System.Data.SqlClient 提供程序;可以通过在 context.Database.DefaultConnectionFactory 上设置不同的 IConnectionFactory 实现来更改此行为。
可以通过将现有 DbConnection 对象传递给 DbContext 构造函数来使用该对象。如果连接对象是 EntityConnection 的实例,则将使用连接中指定的模型,而不使用 Code First 计算模型。如果该对象是其他某一类型(例如 SqlConnection)的实例,则上下文将在 Code First 模式下使用该对象。
可以通过将现有 ObjectContext 传递给 DbContext 构造函数,创建包装现有上下文的 DbContext。对于使用 ObjectContext 但希望在其中一部分利用 DbContext 的现有应用程序,这一点十分有用。
SQL 使用的连接字符串:
1 &connectionStrings&
2 &!--&add name=&eRebateContext& connectionString=&Database=eRebateTServer=10.40.15.16;uid=pwd=a8@MultipleActiveResultSets=true& providerName=&System.Data.SqlClient&/&
3 &add name=&NotesConnection& connectionString=&server=10.40.15.16;database=Duid=pwd=a8@MultipleActiveResultSets=true& providerName=&System.Data.SqlClient&/&--&
4 &add name=&eRebateContext& connectionString=&Database=eRServer=V-BLCHEN-02;Trusted_connection=YMultipleActiveResultSets=True& providerName=&System.Data.SqlClient& /&
5 &add name=&NotesConnection& connectionString=&Database=DServer=V-BLCHEN-02;Trusted_connection=YMultipleActiveResultSets=True& providerName=&System.Data.SqlClient& /&
6 &!--&add name=&eRebateContext& connectionString=&Database=eRServer=10.40.15.81;user=password=mis& providerName=&System.Data.SqlClient&/&
7 &add name=&NotesConnection& connectionString=&Database=DServer=10.40.15.81;user=password=mis& providerName=&System.Data.SqlClient&/&--&
8 &/connectionStrings&
Mysql 使用的连接字符串 ( install Mysql.data.entity )
&connectionStrings&
&add name=&JdCloudDbContext& providerName=&MySql.Data.MySqlClient& connectionString=&server=database=jd_cloud_UID=password=&/&
&/connectionStrings&
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致asp.net 中 EF code first DbContext分别是什么,修改模型后,一定要迁移吗_百度知道
asp.net 中 EF code first DbContext分别是什么,修改模型后,一定要迁移吗
一定要使用迁移吗?我写了一个实体模型,然后继承了一个Dbcontext类EF ,自动生成了表,然后运行,运行就要求我 使用数据迁移,code first, DbContext分别是什么,但是我修改模型定义后
提问者采纳
再编译的话会更新相应的代码,msdn有关于ef的迁徙,code first和model first迁徙很容易失败,再次运行就会覆盖代码,不要手动修改生成的代码,建议使用迁徙,如果是webform的话,然后在model设计器中选择根据DB更新模型,因为有些文件手动修改后,如果使用的是mvc迁徙比较容易,具体的使用可以参见微软的msdnDbContext是根据connectionString生成的数据库上下文类,最好使用database first,如果是修改了模型的话
提问者评价
太给力了,你的回答完美地解决了我的问题,非常感谢!
其他类似问题
为您推荐:
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁EF code First数据迁移学习笔记 - 推酷
EF code First数据迁移学习笔记
1.新建一个控制台项目, 在&程序包管理控制台&执行 Install-package EntityFramework &//安装EF环境
2.在项目下新建类(Paper),也就是code first中的code。建好之后,Ctrl+Shift+B生成项目。(不生成的话,会出现控制器找不到类型或者其他报错)
3.在app.config或web.config的configuration下添加节点connectionStrings:
&connectionStrings&
&add name=&DefaultConnection& connectionString=&Data Source=.;Initial Catalog=MySPersist Security Info=TUser ID=a;Password=b& providerName=&System.Data.SqlClient& /&
&/connectionStrings&
4.项目下新建类SiteDbContext,作为项目的数据上下文:
public class SiteDbContext : DbContext
public SiteDbContext() : base(&DefaultConnection&) { }
public DbSet&Paper& Papers { get; set; }
在类下定义构造函数,传递步骤3的connectionString的name给基类构造函数。这样,数据的获取就会通过步骤3的数据库链接了。同时在数据上下文中定义已经定义好的类的DbSet类型的属性。为后面的迁移做准备。
1.此时,如果直接在program的Main函数中调用SiteDbContext,然后操作下面的Papers数据,会在数据库自动生成Papers表。调试程序。
2.打开迁移:Enable-Migrations
Checking if the context targets an existing database...
Detected database created with a database initializer. Scaffolded migration '371_InitialCreate' corresponding to existing database. To use an automatic migration instead, delete the Migrations folder and re-run Enable-Migrations specifying the -EnableAutomaticMigrations parameter.
Code First Migrations enabled for project MigrationTest.
执行完命令后,在项目中自动生成文件夹Migrations,以及文件夹下面的Configuration.cs和371_InitialCreate.cs
1.修改类Paper的结构,在这里,我们新增属性public string Test{},生成程序。
2.为了验证数据库会不会全部重新生成,我们在数据库里手动插入几条数据:
3.增加迁移的节点:Add-Migration PaperTest(在前面操作的基础上,执行这条命令时,程序会自动判断在上次迁移基础上的修改)
执行完上面的命令后,会在文件夹Migrations下自动生成一个类:
public partial class PaperTest : DbMigration
public override void Up()
AddColumn(&dbo.Papers&, &Test&, c =& c.String());
public override void Down()
DropColumn(&dbo.Papers&, &Test&);
class的名称是上面Add后面定义的。而类下面有两个方法,一个是Up,一个是Down。在Up里面,记录了需要升级的修改,这里也就是Papers表格增加了列Test。只要我们在后面执行Update-Database,就会执行此类下面的Up函数。
这里的Down函数简单介绍就是,为了回滚修改而设计的。如果用户希望恢复到某一个迁移节点,程序会自动根据已经执行的迁移,判断回滚哪些迁移,执行他们的Down函数。
4.执行Update-Database,将这里的修改升级到数据库。
查看提示,在Update命令后面输入参数-Verbose可以查看升级的明细。
第二行,运行迁移对象423_PaperTest。
第三行,运行Seed函数。这里说明一下,Seed函数在Configuration.cs里面:
protected override void Seed(MigrationTest.SiteDbContext 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. E.g.
// context.People.AddOrUpdate(
p =& p.FullName,
new Person { FullName = &Andrew Peters& },
new Person { FullName = &Brice Lambson& },
new Person { FullName = &Rowan Miller& }
仔细查看注释的语句,可以看到,这个函数在每次迁移到最新版本时调用。用AddOrUpdate函数可以避免生成重复的数据。最后面给了一个AddOrUpdate的调用示例。
这个函数的用处,我暂时理解为,生成初始化数据。不管怎么迁移,都会存在这些数据。
5.执行完上面的操作后,再回到数据库,查看数据结构和数据内容:
到此,在现有的类上面增加属性的操作完成了。
删除属性的操作和增加属性的操作差不多。首先修改类结构,屏蔽上面的//public string Test { }。然后Add一个迁移节点,命名为DelPaperTest。执行此命令,生成相应的迁移类文件。最后执行Update-Database,在这里我们用Update-Database -Verbose命令,查看一下执行的详细内容:
PM& Update-Database -Verbose
Using StartUp project 'MigrationTest'.
Using NuGet project 'MigrationTest'.
Specify the '-Verbose' flag to view the SQL statements being applied to the target database.
Target database is: 'MySite' (DataSource: ., Provider: System.Data.SqlClient, Origin: Configuration).
Applying explicit migrations: [534_DelPaperTest].
Applying explicit migration: 534_DelPaperTest.
DECLARE @var0 nvarchar(128)
SELECT @var0 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.Papers')
AND col_name(parent_object_id, parent_column_id) = 'Test';
IF @var0 IS NOT NULL
EXECUTE('ALTER TABLE [dbo].[Papers] DROP CONSTRAINT [' + @var0 + ']')
ALTER TABLE [dbo].[Papers] DROP COLUMN [Test]
INSERT [dbo].[__MigrationHistory]([MigrationId], [ContextKey], [Model], [ProductVersion])
VALUES (N'534_DelPaperTest', N'MigrationTest.SiteDbContext',
0x1F8...00 , N'6.1.2-31219')
Running Seed method.
查看上面内容里面的sql语句,首先寻找列Test相关的约束,如果有,先删除约束。然后删除列,最后在迁移历史表里面写入一行迁移记录。
1.在Paper类下修改属性名称,生成项目:
public string Desc { get; set; }
public string DescAA { get; set; }
2.按照常规的方法,接下来我们应该添加一个迁移的节点。首先我们看看这样执行有什么样的结果:
Add-Migration ModifyPaper
打开自动生成的迁移类文件314_ModifyPaper.cs:
public partial class ModifyPaper : DbMigration
public override void Up()
AddColumn(&dbo.Papers&, &DescAA&, c =& c.String());
DropColumn(&dbo.Papers&, &Desc&);
public override void Down()
AddColumn(&dbo.Papers&, &Desc&, c =& c.String());
DropColumn(&dbo.Papers&, &DescAA&);
可以看到在Up里面,它不是直接修改了列的名称,而是先增加新列DescAA,然后删除旧列Desc。这样执行有一个后果,如果列里面有数据,则数据全部丢失。
3.执行Update-Database的结果如下:
如何才能在保留现有数据的基础上修改列名呢?
(常规操作中,不建议类似这样修改列名的操作,因为数据库的调用可能不止这一处,容易产生漏改而出现bug)
注意:修改列名见下面的方法三。下面的内容已过时,留文仅作记录。
1.直接修改类属性Desc为DescAA,同时,手动修改数据库列名为DescAA。运行程序,会报错:
2.在运行程序前,删除迁移文件夹Migrations。然后运行程序,同样报上面的错误。
3.项目中执行命令Enable-Migrations,重新生成迁移文件夹。然后运行程序,同样报错。
4.删除数据库中迁移历史表中的项目相关的迁移记录,同时删除项目中的Migrations文件夹,然后再执行Enable-Migrations,会看到:
同时 Migrations文件夹下除了Configuration.cs,没有任何其他的类文件。
到此,修改类结构的属性名称完成,同时成功保住了数据库的现有数据。
但是此方法,有一个陷阱。
如果在修改属性之后,又有增属性或者删属性的操作,在Add-Migration之后,自动生成的类里面,会出现这样的代码:
public partial class DelTestAfterChangeDescAA : DbMigration
public override void Up()
CreateTable(
&dbo.Papers&,
PaperID = c.Int(nullable: false, identity: true),
PaperName = c.String(),
DescAA = c.String(),
.PrimaryKey(t =& t.PaperID);
public override void Down()
DropTable(&dbo.Papers&);
上面的代码直接CreateTable和DropTable。这是 执行Update-Database会提示失败,因为数据库已有表Papers
这时,我们可以选择手动的修改Up和Down的内容:
public partial class DelTestAfterChangeDescAA : DbMigration
public override void Up()
DropColumn(&dbo.Papers&, &Test&);
public override void Down()
AddColumn(&dbo.Papers&, &Test&, c =& c.String());
执行Update-Database,命令完成。
注意:修改列名见下面的方法三。下面的内容已过时,留文仅作记录。
1.在上面的基础上,修改Paper类的DescAA为Desc。
2.运行Add-Migration ModifyDescAA,得到迁移cs文件, 手动注释其中Up的DropColumn :
public partial class ModifyDesc : DbMigration
public override void Up()
AddColumn(&dbo.Papers&, &Desc&, c =& c.String());
//DropColumn(&dbo.Papers&, &DescAA&);
public override void Down()
//AddColumn(&dbo.Papers&, &DescAA&, c =& c.String());
DropColumn(&dbo.Papers&, &Desc&);
3.执行Update-Database。这时,数据库的Papers表新增列Desc。
4.进入数据库,手动删除刚才新增的Desc列,同时,将DescAA列名修改成Desc。
5.运行程序,可以调试,说明上面的修改属性名操作成功。
6.为了防止以后迁移到某个特定的版本时,回滚出现问题。手动屏蔽上面2步骤中Up和Down中的代码.
这里留意:不能手动删除迁移历史表中的刚才一行迁移历史,同时手动删除项目中上面2步骤生成的cs文件。这样会直接报上面的&数据库上下文已改&错。
上面这两种方法,操作完了之后都需要做一定工作量的修补,否则下面的Code first就会有些隐患。
第三种方法
在调试完上面两种方法后,发现DbMigration有RenameColumn的函数。
呵呵,在这个函数的基础上,修改属性名称就变得超级简单了。
1.修改Paper的DescAA,改成Desc
2.执行Add-Migration RenameDesc命令,生成迁移类文件,手动修改类文件内容如下:
public partial class RenameDesc : DbMigration
public override void Up()
//AddColumn(&dbo.Papers&, &Desc&, c =& c.String());
//DropColumn(&dbo.Papers&, &DescAA&);
RenameColumn(&dbo.Papers&, &DescAA&, &Desc&);
public override void Down()
//AddColumn(&dbo.Papers&, &DescAA&, c =& c.String());
//DropColumn(&dbo.Papers&, &Desc&);
RenameColumn(&dbo.Papers&, &Desc&, &DescAA&);
3.执行Update-Database命令,数据库列名被自动修改。
这里值得注意的是,在执行Update命令时,程序会提醒操作着,修改列名可能会导致存储过程及其他调用列的sql脚本失效:
这是在实际操作中要注意的问题,也正是笔者不建议随便修改列名的主要原因——可能导致其他调用失效。
笔者小记:
边摸索边操作,到这里,对EF的code first架构算是有了一定的了解
1.迁移的关联在数据库的迁移历史表和项目的Migrations文件夹下的继承了DbMigration的cs文件
2.在数据库的迁移历史表中,字段Model有一些加了密的迁移映射,随意删除修改会导致&数据库上下文被改&的错误。
3.Migrations文件夹下的继承了DbMigration的cs文件可以手动修改,这里的修改可以非常灵活,表格和表格字段的增删改,在这里都有。
理解了上面的这些点,简单使用以code first为基础的EF,应该没什么问题了。
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致}

我要回帖

更多关于 ef6 code first 教程 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信