EF | Entity framework

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>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值