本文主要介绍在ASP.NET MVC5和EntityFramework6.x环境下,在使用ADO.NET实体数据模型时,两个选项:来自数据库的EF设计器和来自数据库的CodeFirst的区别。
为了测试,在数据库中建立Test数据库,并建立User表:
CREATE TABLE [dbo].[User] (
[Id] INT NOT NULL,
[Name] NCHAR (10) NOT NULL,
[Age] INT NOT NULL,
[Gender] NCHAR (10) NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
1.来自数据库的EF设计器
1.1 按照实体数据模型向导一步一步往下走
这里可以看到自动生成的连接字符串和连接名。
选择我们需要的实体
下面就是生成的模型,可以看到和数据库里的表结构是一一对应的:
我们还可以看到生成了好多的东西:
User.cs
是向导根据数据库自动生成的User类,说明使用“来自数据库的EF设计器”时,不需要有实体类,这也就是DataFirst模式。
UserModel.Context.cs
文件里包含的TestEntities
类是向导生成的数据上下文类,该类用于映射数据库,在控制器中对数据模型进行操作时都要先对其实例化,name=TestEntities
是连接数据库字符串的名称。
<connectionStrings>
<add name="TestEntities" connectionString="metadata=res://*/UserModel.csdl|res://*/UserModel.ssdl|res://*/UserModel.msl;provider=System.Data.SqlClient;provider connection string="data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\Test.mdf;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
1.2 根据该模型创建包含视图的mvc5控制器(使用EF)
创建控制器后我们可以在控制器类中看到实例化数据上下文类的代码private TestEntities db = new TestEntities();
2.来自数据库的CodeFirst
2.1 按照实体数据模型向导创建“来自数据库的CodeFirst模型(过程和第1部分一样)
生成的数据库连接字符串为:
<add name="SecondModel" connectionString="data source=(LocalDB)\MSSQLLocalDB;attachdbfilename=|DataDirectory|\Test.mdf;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework" providerName="System.Data.SqlClient" />
2.2 上一步完成后,在项目中生成了数据上下文类SecondModel.cs
和实体类User.cs
:
public partial class SecondModel : DbContext
{
public SecondModel()
: base("name=SecondModel")
{
}
public virtual DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(e => e.Name)
.IsFixedLength();
modelBuilder.Entity<User>()
.Property(e => e.Gender)
.IsFixedLength();
}
}
[Table("User")]
public partial class User
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[StringLength(10)]
public string Name { get; set; }
public int Age { get; set; }
[Required]
[StringLength(10)]
public string Gender { get; set; }
}
3.两种方式对比
3.1 连接数据库字符串对比:
第一种方式生成的字符串要比第二种多了一个metadata参数:metadata=res://*/UserModel.csdl|res://*/UserModel.ssdl|res://*/UserModel.msl;
,这句话的意思是加载所有目录下的UserModel.csdl、ssdl、msl文件。
- csdl:类定义实体模型,该文件配置的是将要生成的实体模型类
<EntityType Name="User">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<Property Name="Name" Type="String" MaxLength="10" FixedLength="true" Unicode="true" Nullable="false" />
<Property Name="Age" Type="Int32" Nullable="false" />
<Property Name="Gender" Type="String" MaxLength="10" FixedLength="true" Unicode="true" Nullable="false" />
</EntityType>
- msl:定义实体模型和数据库间属性的映射
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
<EntityContainerMapping StorageEntityContainer="TestModelStoreContainer" CdmEntityContainer="TestEntities">
<EntitySetMapping Name="User">
<EntityTypeMapping TypeName="TestModel.User">
<MappingFragment StoreEntitySet="User">
<ScalarProperty Name="Id" ColumnName="Id" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="Age" ColumnName="Age" />
<ScalarProperty Name="Gender" ColumnName="Gender" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
</EntityContainerMapping>
</Mapping>
- ssdl:根据数据库内部的属性生成的文件
<EntityType Name="User">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false" />
<Property Name="Name" Type="nchar" MaxLength="10" Nullable="false" />
<Property Name="Age" Type="int" Nullable="false" />
<Property Name="Gender" Type="nchar" MaxLength="10" Nullable="false" />
</EntityType>
这种数据库与实体之间的映射配置方便以后对数据库或实体类一方进行修改时,另一方的修改只需要修改映射文件就行了
3.2 生成文件的对比
- 第一种方式生成了一个edmx文件,其中包括了生成的实体类、数据上下文类、实体关系图、以及t4生成器
- 第二种方式只生成了实体类和数据上下文类
- 对比两种方式生成的实体类:
public partial class User
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
[Table("User")]
public partial class User
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
[Required]
[StringLength(10)]
public string Name { get; set; }
public int Age { get; set; }
[Required]
[StringLength(10)]
public string Gender { get; set; }
}
第二种生成的代码要详细一些,可以直接用作Model,而不用再修改或添加注解。
4.个人总结
- 如果数据库已经设计好,推荐使用第一种方式
- 第二种方式如果后期修改了数据库,那么实体类重新生成比较方便,而第一种方式数据库修改后,只需更新一下模型,该过程学习成本高一些
- 各位大神帮我想想他们的优缺点吧