EF | Entity framework

来源:互联网 发布:加索尔数据 编辑:程序博客网 时间:2024/06/11 15:34

1

首先在项目中添加一个ADO.NET实体数据模型,选好需要的表后,完成。然后它就会自动给我们应用了如下这些类库,下面是介绍这些类库的作用,及对edmx这个XML文件进行介绍


关于edmx文件的介绍  (如何查看这个Model1.edmx文件的XML文件呢?Model1.edmx-->(右键)打开方式-->XML(文本)编辑器)


展开来看看


<?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="salesModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2008" Alias="Self" xmlns:store="http://schemas.microsoft.com/ado/2007/12/edm/EntityStoreSchemaGenerator" xmlns="http://schemas.microsoft.com/ado/2009/11/edm/ssdl">        <EntityType Name="T_User">          <Key>            <PropertyRef Name="Id" />          </Key>          <Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />          <Property Name="UserName" Type="nvarchar" MaxLength="50" Nullable="false" />          <Property Name="Password" Type="varchar" MaxLength="50" Nullable="false" />          <Property Name="Email" Type="varchar" MaxLength="50" Nullable="false" />          <Property Name="Errors" Type="int" Nullable="false" />          <Property Name="Session" Type="nvarchar" MaxLength="50" Nullable="false" />        </EntityType>        <EntityType Name="T_UserInfo">          <Key>            <PropertyRef Name="Id" />          </Key>          <Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />          <Property Name="UserName" Type="nvarchar" MaxLength="50" />          <Property Name="Name" Type="nvarchar" MaxLength="50" />          <Property Name="Age" Type="int" />          <Property Name="Gender" Type="int" />          <Property Name="Mobile" Type="varchar" MaxLength="50" />          <Property Name="Email" Type="varchar" MaxLength="50" />          <Property Name="Addres" Type="nvarchar" MaxLength="100" />          <Property Name="Remarks" Type="nvarchar" MaxLength="200" />        </EntityType>        <EntityContainer Name="salesModelStoreContainer">          <EntitySet Name="T_User" EntityType="Self.T_User" Schema="dbo" store:Type="Tables" />          <EntitySet Name="T_UserInfo" EntityType="Self.T_UserInfo" Schema="dbo" store:Type="Tables" />        </EntityContainer>      </Schema>    </edmx:StorageModels>    <!-- CSDL content 【第二个节点:这是一个描述实体的配置节】-->    <edmx:ConceptualModels>      <Schema Namespace="salesModel" Alias="Self" annotation:UseStrongSpatialTypes="false" xmlns:annotation="http://schemas.microsoft.com/ado/2009/02/edm/annotation" xmlns="http://schemas.microsoft.com/ado/2009/11/edm">        <!--EntityType表示类 Nmae表示类的名字叫什么-->        <EntityType Name="T_User">          <!--Key表示主键,PropertyRef Name="Id"表示主键为Id-->          <Key>            <PropertyRef Name="Id" />          </Key>          <!--Property表示类中的属性,Name表示属性的名称,Type表示属性的类型,Nullable="false"表示这个字段不能为空,annotation:StoreGeneratedPattern="Identity"表示这个属性是自增的-->          <Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />          <!--MaxLength表示UserName这个属性的最大长度值为50,FixedLength表示是否要固定长度,为true就表示要固定这个长度不变-->          <Property Name="UserName" Type="String" MaxLength="50" FixedLength="false" Unicode="true" Nullable="false" />          <Property Name="Password" Type="String" MaxLength="50" FixedLength="false" Unicode="false" Nullable="false" />          <Property Name="Email" Type="String" MaxLength="50" FixedLength="false" Unicode="false" Nullable="false" />          <Property Name="Errors" Type="Int32" Nullable="false" />          <Property Name="Session" Type="String" MaxLength="50" FixedLength="false" Unicode="true" Nullable="false" />        </EntityType>        <EntityType Name="T_UserInfo">          <Key>            <PropertyRef Name="Id" />          </Key>          <Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />          <Property Name="UserName" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />          <Property Name="Name" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />          <Property Name="Age" Type="Int32" />          <Property Name="Gender" Type="Int32" />          <Property Name="Mobile" Type="String" MaxLength="50" FixedLength="false" Unicode="false" />          <Property Name="Email" Type="String" MaxLength="50" FixedLength="false" Unicode="false" />          <Property Name="Addres" Type="String" MaxLength="100" FixedLength="false" Unicode="true" />          <Property Name="Remarks" Type="String" MaxLength="200" FixedLength="false" Unicode="true" />        </EntityType>        <EntityContainer Name="salesEntities" annotation:LazyLoadingEnabled="true">          <EntitySet Name="T_User" EntityType="Self.T_User" />          <EntitySet Name="T_UserInfo" EntityType="Self.T_UserInfo" />        </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="salesModelStoreContainer" CdmEntityContainer="salesEntities">          <EntitySetMapping Name="T_User">            <EntityTypeMapping TypeName="salesModel.T_User">              <MappingFragment StoreEntitySet="T_User">  <!--Name="Id"表示实体里面的属性名Id   ColumnName="Id"表示数据库表中的Id属性,即实体中的Id对应数据库表中的Id列-->                <ScalarProperty Name="Id" ColumnName="Id" />                <ScalarProperty Name="UserName" ColumnName="UserName" />                <ScalarProperty Name="Password" ColumnName="Password" />                <ScalarProperty Name="Email" ColumnName="Email" />                <ScalarProperty Name="Errors" ColumnName="Errors" />                <ScalarProperty Name="Session" ColumnName="Session" />              </MappingFragment>            </EntityTypeMapping>          </EntitySetMapping>          <EntitySetMapping Name="T_UserInfo">            <EntityTypeMapping TypeName="salesModel.T_UserInfo">              <MappingFragment StoreEntitySet="T_UserInfo">                <ScalarProperty Name="Id" ColumnName="Id" />                <ScalarProperty Name="UserName" ColumnName="UserName" />                <ScalarProperty Name="Name" ColumnName="Name" />                <ScalarProperty Name="Age" ColumnName="Age" />                <ScalarProperty Name="Gender" ColumnName="Gender" />                <ScalarProperty Name="Mobile" ColumnName="Mobile" />                <ScalarProperty Name="Email" ColumnName="Email" />                <ScalarProperty Name="Addres" ColumnName="Addres" />                <ScalarProperty Name="Remarks" ColumnName="Remarks" />              </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="true" />        <DesignerProperty Name="CodeGenerationStrategy" Value="无" />      </DesignerInfoPropertySet>    </Options>    <!-- Diagram content (shape and connector positions) -->    <Diagrams></Diagrams>  </Designer></edmx:Edmx>

我们在来看看Model1.Context.cs这个上下文容器类

//------------------------------------------------------------------------------// <auto-generated>//    此代码是根据模板生成的。////    手动更改此文件可能会导致应用程序中发生异常行为。//    如果重新生成代码,则将覆盖对此文件的手动更改。// </auto-generated>//------------------------------------------------------------------------------namespace WebAppEF{    using System;    using System.Data.Entity;    using System.Data.Entity.Infrastructure;        public partial class salesEntities : DbContext    {        /// <summary>        /// 用来初始化ado.net连接对象        /// </summary>        public salesEntities()            : base("name=salesEntities")//这里调用父类的带一个参数的构造函数,传递的"name=salesEntities"值就表示告诉我们 去web.config配置文件中 找到<connectionStrings>这个节点下name为salesEntities的这个配置节点,用它来初始化我们的ado.net连接对象        {        }            protected override void OnModelCreating(DbModelBuilder modelBuilder)        {            throw new UnintentionalCodeFirstException();        }        //下面我们来看看这个DbSet<T> 这个泛型类。以下是这个类的定义:        // public class DbSet<TEntity> : DbQuery<TEntity>, IDbSet<TEntity>, IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable, IInternalSetAdapter where TEntity: class        //根据DbSet<T>的定义我们可以看到这个泛型类是继承了 IQueryable<TEntity>, IEnumerable<TEntity>, IQueryable, IEnumerable 等接口的        //而在System.Linq命名空间下的Queryable类中,为IQueryable<TEntity> 这个泛型接口扩展了很多方法,如:Where(),Any(),Count(),OrderBy(),,ThenBy(),Groupby(),Join(),Select(),Find(),First(),Last(),FirstOrDefault(),First(),Find(),Single(),Skip(),Take()等方法。而DbSet<T>这个泛型类又是实现了这个IQueryable<TEntity> 接口的,所以DbSet<T>这个泛型类的对象是可以使用IQueryable<TEntity> 接口中的这些扩展方法的。通过这些泛型方法,我们进行数据的相关查询。        //我们在看看这个DbSet<T>泛型类的定义,我们看到它是继承一个 DbQuery<TEntity>的类。而这个DbQuery<TEntity>类也同样实现了Queryable<TEntity>这个泛型接口,所以DbQuery<TEntity>这个泛型类的对象同样也是可以使用Queryable<TEntity>这个泛型接口中的扩展方法的。        //所以综上所述:DbSet<T>这个泛型类的作用就是:用于提供SQO方法,结合程序员写Lambda表达式进行数据的相关查询        public DbSet<T_User> T_User { get; set; }        public DbSet<T_UserInfo> T_UserInfo { get; set; }    }}



EF的查询原理


我们要特别留意这个代理类对象中的State属性的值,它的值是一个枚举类型的值,它的值的作用就告诉EF,生成什么类型的SQL语句(如:insert,update,Delete)


当我们调用db.SaveChanges()方法的时候,就会通知EF容器遍历当前EF容器中所有State为非Detached的代理类对象

再根据代理类对象的State的值,生成相应的Sql语句发送给DB执行,例如

State=EntityState.Added 的时候 ,则生成 Insert 的SQL语句

State=EntityState.Deleted 的时候 ,则生成 Delete的SQL语句

State=EntityState.Modified 的时候 ,则生成 Update的SQL语句

当数据从数据库表中刚查询出来的时候State的状态为 State=EntityState.Unchanged 表示没有改动过。

State=EntityState.Detached 的时候,表示 虽然代理类在EF容器的内部,但是你不需要管我,直接忽略我


我们在来了解一下在EF中,做新增数据的一些注意知识点(获取新增数据的Id)

新增完数据后,model.Id 就可以获取到新增的id  

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.UI;using System.Web.UI.WebControls;namespace WebAppEF{    public partial class WebForm1 : System.Web.UI.Page    {        protected void Page_Load(object sender, EventArgs e)        {            salesEntities db = new salesEntities();            T_UserInfo model=new T_UserInfo(){  Addres="123", Age=25, Name="张三", Gender=1, Email="123@qq.com", Mobile="18620088006", UserName="小张", Remarks="ddd"};            db.T_UserInfo.Add(model);            db.SaveChanges();            Response.Write(model.Id) //这里会打印出插入的那条数据的最新Id        }    }}

当用户在做这一条数据插入的时候,

当 salesEntities db = new salesEntities();就表示创建了EF容器类的对象。

当写完 T_UserInfo model=new T_UserInfo(){  Addres="123", Age=25, Name="张三", Gender=1, Email="123@qq.com", Mobile="18620088006", UserName="小张", Remarks="ddd"}; 这条语句的时候,这个对象还是在应用程序的内存中,与EF还没有联系,

当执行db.T_UserInfo.Add(model);的时候, 这条model对象已经加入到EF容器类中。

在EF容器类中,将这个对象包装成一个代理类对象  (注意此时这个代理类对象里面有一个State=Addend属性,而刚刚我创建model 这条对象的时候并没有写Id这个属性(因为Id是一个自增值),可是它这里将自己添加了一个Id,并初始值为0)


当我们调用db.SaveChanges();的时候,就会通知EF容器遍历当前EF容器中所有State为非Detached的代理类对象,正好在这里找到一个State=Added的代理类对象,然后就生成了Insert的SQL语句,发给DB执行。

我们同过SQL server Profiler监控工具,发现这条SQL语句是这样的

exec sp_executesql N'insert [dbo].[T_UserInfo]([UserName], [Name], [Age], [Gender], [Mobile], [Email], [Addres], [Remarks])values (@0, @1, @2, @3, @4, @5, @6, @7)select [Id]from [dbo].[T_UserInfo]where @@ROWCOUNT > 0 and [Id] = scope_identity()',N'@0 nvarchar(50),@1 nvarchar(50),@2 int,@3 int,@4 varchar(50),@5 varchar(50),@6 nvarchar(100),@7 nvarchar(200)',@0=N'小张',@1=N'张三',@2=25,@3=1,@4='18620997006',@5='123@qq.com',@6=N'123',@7=N'ddd'

注意,这条SQL 存储过程执行插入语句,语句中并没有包含代理类中的Id属性的。(因为T_UserInfo表中的Id字段为自增字段,不需要赋值。所以这里不要包含),但是我们插入了一条新的数据后,我们怎么知道插入的那条数据的Id是多少呢?

当DB执行完这条插入语句的存储过程的时候,马上又执行了以下查询语句:

select [Id]

from [dbo].[T_UserInfo]
where @@ROWCOUNT > 0 and [Id] = sscope_identity()....

其中scope_identity()表示获取最后一条数据的标识值。 通过这条语句 就将刚刚插入进去的那条数据的Id 就拿到了。然后在通过Ado.net将这个Id交给EF,EF在将这个代理类中的Id的值从0改为从数据库返回的新值。
所以当一条数据成功插入后,我们就可以用model.Id 来得到这条新增的数据的Id值。


注意点

将来有一天,我们要建一个类库,在类库中添加了EF ,你想要在UI层去使用,就必须将类库中App.config配置文件中的一下三个配置节点复制到UI层中的Web.config配置文件中去

<configSections>    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />  </configSections>     <connectionStrings>    <add name="salesEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=.;initial catalog=sales;persist security info=True;user id=sa;password=123456;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />  </connectionStrings>  <entityFramework>    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">      <parameters>        <parameter value="v11.0" />      </parameters>    </defaultConnectionFactory>  </entityFramework>


0 0
原创粉丝点击