entity framework中的edmx文件作为代码与数据库沟通的桥梁,作用是至关重要的。如果edmx文件出了问题,ef就基本上没得用了。虽然edmx文件是由ef自动生成的,但是一些特定的操作可能会引发ef的bug,从而导致edmx文件出错,并且无法使用“从数据库更新模型”命令来修复,删除edmx重建又要在新的edmx中重新声明大量枚举类型,这个时候,理解ef的内部结构就显得很必要了。

我们创建一个简单的数据库,里面只有一张User表,表中有Id,Name,Type三个字段,其中Id为主键int型,Name为nvarchar型,最大长度为500,Type为int型,实体类中对应为枚举。

创建完毕后,用文本编辑器打开edmx文件,如下:

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="3.0" xmlns:edmx="http://schemas.microsoft.com/ado/2009/11/edmx">
<!-- EF Runtime content -->
<edmx:Runtime>
<!-- SSDL content -->
<edmx:StorageModels>
<Schema Namespace="edmxModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">
<EntityType Name="User">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" Nullable="false" />
<Property Name="Name" Type="nvarchar" MaxLength="500" />
<Property Name="Type" Type="int" Nullable="false" />
</EntityType>
<EntityContainer Name="edmxModelStoreContainer">
<EntitySet Name="User" EntityType="Self.User" Schema="dbo" store:Type="Tables" />
</EntityContainer>
</Schema>
  </edmx:StorageModels>
<!-- CSDL content -->
<edmx:ConceptualModels>
<Schema Namespace="edmxModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns:customannotation="http://schemas.microsoft.com/ado/2013/11/edm/customannotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">
<EntityType Name="User">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Int32" Nullable="false" />
<Property Name="Name" Type="String" MaxLength="500" FixedLength="false" Unicode="true" />
<Property Name="Type" Type="Int32" Nullable="false" />
</EntityType>
<EntityContainer Name="edmxEntities" annotation:LazyLoadingEnabled="true">
<EntitySet Name="User" EntityType="Self.User" />
</EntityContainer>
</Schema>
</edmx:ConceptualModels>
<!-- C-S mapping content -->
<edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
<EntityContainerMapping StorageEntityContainer="edmxModelStoreContainer" CdmEntityContainer="edmxEntities">
<EntitySetMapping Name="User">
<EntityTypeMapping TypeName="edmxModel.User">
<MappingFragment StoreEntitySet="User">
<ScalarProperty Name="Type" ColumnName="Type" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="Id" ColumnName="Id" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
</edmx:Runtime>
<!-- EF Designer content (DO NOT EDIT MANUALLY BELOW HERE) -->
<Designer xmlns="http://schemas.microsoft.com/ado/2009/11/edmx">
<Connection>
<DesignerInfoPropertySet>
<DesignerProperty Name="MetadataArtifactProcessing" Value="EmbedInOutputAssembly" />
</DesignerInfoPropertySet>
</Connection>
<Options>
<DesignerInfoPropertySet>
<DesignerProperty Name="ValidateOnBuild" Value="true" />
<DesignerProperty Name="EnablePluralization" Value="false" />
<DesignerProperty Name="IncludeForeignKeysInModel" Value="true" />
<DesignerProperty Name="UseLegacyProvider" Value="false" />
<DesignerProperty Name="CodeGenerationStrategy" Value="无" />
</DesignerInfoPropertySet>
</Options>
<!-- Diagram content (shape and connector positions) -->
<Diagrams></Diagrams>
</Designer>
</edmx:Edmx>

只要认真看一遍,就会发现edmx文件主要分成了三大部分:数据库部分、实体部分、映射部分。

数据库部分为<edmx:StorageModels> (edmx存储模型)标签以内的内容,记录了数据库中各个表的表名、字段以及数据类型。

实体部分为<edmx:ConceptualModels>(edmx概念模型)标签以内的内容,记录了用来承载数据的实体类的相关信息。

映射部分为<edmx:Mappings>以内的内容,记录了每张表与相应的实体类中所有字段与属性的映射关系。如果你尝试在edmx模型视图中修改一个字段并保存,再用文本编辑器打开edmx文件,你就会发现mapping部分中对应的实体属性发生了变化,而数据库部分没有发生改变。利用这个功能可以实现数据库的字段名与实体的属性名不一致但仍能映射,但不推荐这么做,因为你一旦删除edmx重建,你就可能要再起一次别名。

接下来,我们尝试往edmx模型中添加枚举类。做法为edmx模型视图上右键->模型浏览器->枚举类型上添加新的枚举类,最下方勾选引用外部的枚举类型,填上之前定义好的枚举类的命名空间+类名(如 Demo.Model.Type),确认后保存,再用文本编辑器打开edmx文件,就会发现实体部分多出了一条EnumType标签。如:

        <EnumType Name="Type" a:ExternalTypeName="EdmxTest.Enum.Type" xmlns:a="http://schemas.microsoft.com/ado/2006/04/codegeneration" />

EnumType标签往往出现在实体部分的末尾,也就是</Schema>标签的上方,利用这一点我们可以很方便的实现Enum记录的备份。

在大型项目多人协同开发的时候,如果某个成员对edmx文件进行了一些不正确的合并操作或者一些可能会引发bug的操作,edmx文件很可能会损坏,调用ef的时候就会报一些莫名其妙的错误。这个时候最简单也是最快捷的方法,就是果断的删除edmx模型重建,而不要用文本编辑器去试图解决问题。因为面对大型项目中上千行的edmx文件,用文本编辑器修好的可能性实在是太小了。

当添加一个edmx模型的时候你会发现系统自动为我们生成了***.desinger.cs、***.tt、***.Context.tt、***.edmx.diagram文件。desinger和edmx.diagram分别为旧版context和图表文件,在开发中一般用处不大。其中desinger文件如果edmx启用了旧的objectcontext策略就会生成内容,并且需要项目引用system.data.entity程序集,否则会报错。如果你不想引用,只需要在desinger文件上右键->属性,生成操作选择无即可。

05-11 22:05