Entity Framework4.0 (四) EF4的内部结构和几个基本概念(转)
前面,大致概述了三种使用EF4构造应用的方法:1.Database First方法。2.Model First 方法。3.Code First 方法。因为是概述,所以没深入也没拓宽。
这次我就按自己的理解去试着揭一揭,EF4的面纱。呵呵,讲述EF4的内部结构。
1. Entity Designer(实体设计器)
Designer提供一个直观的方式,使我们可以创建、修改实体,创建、修改关联,及实体和关联与数据库之间的映射方式。基本上都是鼠标点击、拖拽操作,只有大家多动手,多实践,才能更快更好地使用该设计器。最终在自己的项目中熟练、准确地使用它。
2. ObjectContext(对象上下文):管理与数据库的连接,跟踪、管理对象的状态变化、多线程同步/异步,对象信息同步等。负责把数据库中数据字段映射成内存中对象,并管理这些对象。
3. Entity (实体)和Entity Set(实体集):数据表中的每一行数据,在内存中表现为一个实体(对象)。数据表中的多行数据(如筛选结果为多行),在内存中表现为实体(对象)集合。
4. Scalar Property(标量属性)、Complex Property(复杂属性)、Navigation Property(导航属性):原子属性既是标量属性(如“姓氏”是一个标量属性,“名字”也是一个标量属性)。由多个标量属性组合成的属性叫复杂属性 (如“姓氏”和“名字”组合起来成为一个复杂属性“姓名”。)在设计实体时,我们可以用复杂属性去把几个标量属性组合起来,当作一个属性使用;而当我们把 这个复杂属性映射到数据库中数据列时,会把复杂属性拆开成多个标量属性。把拆成的每一个标量属性映射成一列。复杂属性作为一个整体,只会在概念层出现,在 存储层没有复杂属性。因为它已经被拆成多个标量属性了。
5. Relationship 和Association:Relationship 翻译过来是“关系”(一对一,一对多,多对多共三种,表示“某一端的重数”),是一个抽象的概念,用于表示实体与实体的一种对应情况。和数据库中表与表的 “关系”是一样的:Association翻译过来是“关联”或“联系”,反映到界面上就是指设计图中的一条线。表示的是一个实体可以导航到另一个实体, 并不表示“重数”。只有把它们二者结合起来,才能既表示“导航”又表示“重数”。
6. *.edmx文件的结构
在项目中的*.edmx文件上右键-》Open with... -> Xml 编辑器。点击“确定”,观察*.Edmx文件是一个Xml文件。
该Xml文件内,首先看 <edmx:Runtime></edmx:Runtime>节点。<edmx:Runtime>节点内有三个子节点:
- <edmx:StorageModels> <edmx:StorageModels> 节点是SSDL(Storage Schema Definition Language)。主要是对物理存储层上的数据库、数据表、字段的描述。内部有包含实体和关联的子节点。
- <edmx:ConceptualModels> <edmx:ConceptualModels> 节点 是 CSDL (Conceptual Schema Definition Language) 。主要是概念层,实体类,实体类集合,实体属性的描述。开发人员直接使用概念层定义的实体类和属性。内部有包含数据表和关联的子节点。
- <edmx:Mappings> <edmx:Mappings> 节点是 C-S mapping (Conceptual-Storage-Mapping)。主要是将CSDL中定义的实体和关联映射到SSDL中的数据表和关联。
下面是EFDemo中的*.edmx的xml的形式。
<?xml version="1.0" encoding="utf-8"?> <edmx:Edmx Version="2.0" xmlns:edmx="http://schemas.microsoft.com/ado/2008/10/edmx"> <!-- EF Runtime content --> <edmx:Runtime> <!-- SSDL content --> <edmx:StorageModels> <Schema Namespace="NorthwindModel.Store" Alias="Self" Provider="System.Data.SqlClient" ProviderManifestToken="2008" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/02/edm/ssdl"> <EntityContainer Name="NorthwindModelStoreContainer"> <EntitySet Name="Categories" EntityType="NorthwindModel.Store.Categories" store:Type="Tables" Schema="dbo" /> <EntitySet Name="Products" EntityType="NorthwindModel.Store.Products" store:Type="Tables" Schema="dbo" /> <AssociationSet Name="FK_Products_Categories" Association="NorthwindModel.Store.FK_Products_Categories"> <End Role="Categories" EntitySet="Categories" /> <End Role="Products" EntitySet="Products" /> </AssociationSet> </EntityContainer> <EntityType Name="Categories"> <Key> <PropertyRef Name="CategoryID" /> </Key> <Property Name="CategoryID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> <Property Name="CategoryName" Type="nvarchar" Nullable="false" MaxLength="15" /> <Property Name="Description" Type="ntext" /> <Property Name="Picture" Type="image" /> </EntityType> <EntityType Name="Products"> <Key> <PropertyRef Name="ProductID" /> </Key> <Property Name="ProductID" Type="int" Nullable="false" StoreGeneratedPattern="Identity" /> <Property Name="ProductName" Type="nvarchar" Nullable="false" MaxLength="40" /> <Property Name="SupplierID" Type="int" /> <Property Name="CategoryID" Type="int" /> <Property Name="QuantityPerUnit" Type="nvarchar" MaxLength="20" /> <Property Name="UnitPrice" Type="money" /> <Property Name="UnitsInStock" Type="smallint" /> <Property Name="UnitsOnOrder" Type="smallint" /> <Property Name="ReorderLevel" Type="smallint" /> <Property Name="Discontinued" Type="bit" Nullable="false" /> </EntityType> <Association Name="FK_Products_Categories"> <End Role="Categories" Type="NorthwindModel.Store.Categories" Multiplicity="0..1" /> <End Role="Products" Type="NorthwindModel.Store.Products" Multiplicity="*" /> <ReferentialConstraint> <Principal Role="Categories"> <PropertyRef Name="CategoryID" /> </Principal> <Dependent Role="Products"> <PropertyRef Name="CategoryID" /> </Dependent> </ReferentialConstraint> </Association> </Schema> </edmx:StorageModels> <!-- CSDL content --> <edmx:ConceptualModels> <Schema Namespace="NorthwindModel" Alias="Self" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2008/09/edm"> <EntityContainer Name="NorthwindEntities" annotation:LazyLoadingEnabled="true"> <EntitySet Name="Categories" EntityType="NorthwindModel.Category" /> <EntitySet Name="Products" EntityType="NorthwindModel.Product" /> <AssociationSet Name="FK_Products_Categories" Association="NorthwindModel.FK_Products_Categories"> <End Role="Categories" EntitySet="Categories" /> <End Role="Products" EntitySet="Products" /> </AssociationSet> </EntityContainer> <EntityType Name="Category"> <Key> <PropertyRef Name="CategoryID" /> </Key> <Property Name="CategoryID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" /> <Property Name="CategoryName" Type="String" Nullable="false" MaxLength="15" Unicode="true" FixedLength="false" /> <Property Name="Description" Type="String" MaxLength="Max" Unicode="true" FixedLength="false" /> <Property Name="Picture" Type="Binary" MaxLength="Max" FixedLength="false" /> <NavigationProperty Name="Products" Relationship="NorthwindModel.FK_Products_Categories" FromRole="Categories" ToRole="Products" /> </EntityType> <EntityType Name="Product"> <Key> <PropertyRef Name="ProductID" /> </Key> <Property Name="ProductID" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" /> <Property Name="ProductName" Type="String" Nullable="false" MaxLength="40" Unicode="true" FixedLength="false" /> <Property Name="SupplierID" Type="Int32" /> <Property Name="CategoryID" Type="Int32" /> <Property Name="QuantityPerUnit" Type="String" MaxLength="20" Unicode="true" FixedLength="false" /> <Property Name="UnitPrice" Type="Decimal" Precision="19" Scale="4" /> <Property Name="UnitsInStock" Type="Int16" /> <Property Name="UnitsOnOrder" Type="Int16" /> <Property Name="ReorderLevel" Type="Int16" /> <Property Name="Discontinued" Type="Boolean" Nullable="false" /> <NavigationProperty Name="Category" Relationship="NorthwindModel.FK_Products_Categories" FromRole="Products" ToRole="Categories" /> </EntityType> <Association Name="FK_Products_Categories"> <End Role="Categories" Type="NorthwindModel.Category" Multiplicity="0..1" /> <End Role="Products" Type="NorthwindModel.Product" Multiplicity="*" /> <ReferentialConstraint> <Principal Role="Categories"> <PropertyRef Name="CategoryID" /> </Principal> <Dependent Role="Products"> <PropertyRef Name="CategoryID" /> </Dependent> </ReferentialConstraint> </Association> </Schema> </edmx:ConceptualModels> <!-- C-S mapping content --> <edmx:Mappings> <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2008/09/mapping/cs"> <EntityContainerMapping StorageEntityContainer="NorthwindModelStoreContainer" CdmEntityContainer="NorthwindEntities"> <EntitySetMapping Name="Categories"><EntityTypeMapping TypeName="NorthwindModel.Category"><MappingFragment StoreEntitySet="Categories"> <ScalarProperty Name="CategoryID" ColumnName="CategoryID" /> <ScalarProperty Name="CategoryName" ColumnName="CategoryName" /> <ScalarProperty Name="Description" ColumnName="Description" /> <ScalarProperty Name="Picture" ColumnName="Picture" /> </MappingFragment></EntityTypeMapping></EntitySetMapping> <EntitySetMapping Name="Products"> <EntityTypeMapping TypeName="IsTypeOf(NorthwindModel.Product)"> <MappingFragment StoreEntitySet="Products"> <ScalarProperty Name="Discontinued" ColumnName="Discontinued" /> <ScalarProperty Name="ReorderLevel" ColumnName="ReorderLevel" /> <ScalarProperty Name="UnitsOnOrder" ColumnName="UnitsOnOrder" /> <ScalarProperty Name="UnitsInStock" ColumnName="UnitsInStock" /> <ScalarProperty Name="UnitPrice" ColumnName="UnitPrice" /> <ScalarProperty Name="QuantityPerUnit" ColumnName="QuantityPerUnit" /> <ScalarProperty Name="CategoryID" ColumnName="CategoryID" /> <ScalarProperty Name="SupplierID" ColumnName="SupplierID" /> <ScalarProperty Name="ProductName" ColumnName="ProductName" /> <ScalarProperty Name="ProductID" ColumnName="ProductID" /> </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/2008/10/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" /> </DesignerInfoPropertySet> </Options> <!-- Diagram content (shape and connector positions) --> <Diagrams> <Diagram Name="Northwind"> <EntityTypeShape EntityType="NorthwindModel.Category" Width="1.5" PointX="1.5" PointY="0.875" Height="1.7908333333333335" IsExpanded="true" /> <EntityTypeShape EntityType="NorthwindModel.Product" Width="1.5" PointX="3.75" PointY="0.625" Height="2.8025520833333331" IsExpanded="true" /> <AssociationConnector Association="NorthwindModel.FK_Products_Categories" ManuallyRouted="false"> <ConnectorPoint PointX="3" PointY="1.7704166666666668" /> <ConnectorPoint PointX="3.75" PointY="1.7704166666666668" /> </AssociationConnector> </Diagram> </Diagrams> </Designer> </edmx:Edmx>
7. EDM生成的类:当我们使用EDM向导时(不论是Model First还是Database First),设计器会利用EntityModelCodeGenerator这个工具去生成一个文件*.edmx.cs。该文件中产生相应的类及属性。
- 容器类:默认情况下会以App.Config连接字符串名字生成一个容器类,如(NorthwindEntities)。容器类从 ObjectContext继承而来。容器类含有可以返回任何一个实体的集合的属性,如Products属性将返回一 个 ObjectSet<Product>集合。
- 实体类:每一个数据表会生成一个实体类(如Product)。实体类从EntityObject继承而来。每一个实体类都有一个工厂方法,如 CreateProduct(Int32 productID, String productName, Boolean discontinued),参数是在数据库中该表的非空字段所对应的属性。
- 容器类和实体类都是Partial 类。这样你可以在不同的地方(*cs文件中)定义同一个类,在编译时不同文件中的定义部分是合并到一起,编译成一个整体类的。使用过WPF的朋友,应该对 这partial 不陌生。使用partial的好处之一是在项目开发的任何一阶段可以方便地对已有类进行灵活扩展。