• MVC的学习-EF的认识


    1.什么是EF

    EF又称持久层框架:平时C#定义的变量是保存到内存中的,一断电就没有了。而持久的意思是数据保存到硬盘盘里(数据库的sql查询是在硬盘里进行的,所以速度很慢)。EF帮我们将一个对象保存到数据库中,框架为我们自动生成相应的Sql与,通过ADO.NET向数据库发送命令。

    2.EF包含哪些内容

    a.怎么创建一个EF文件:

    在VS中,新建一个ADO.NET实体数据模型。它会为我们生成一个后缀为edmx的文件。EF为我们做了三件事:生成一个XML文件(t4模板通过该xml新生产实体类和上下文对象);创建一个实体类(包含要处理对象的信息),添加一个数据上下文(EF上下文,通过该对象可以把内存中的数据添加到数据库)

    通过查看,edmx其实就是一个xml文件。它主要包含三部分:数据实体的信息,模型对象的信息,映射信息。还有一个edmx设计器(Designer)

    数据实体(StorageModels)

    它包含了数据库的信息(什么数据库,数据库版本,数据库提供程序),表的信息(表名,表的主键,表中各字段的信息,实体容器信息)

    <edmx:StorageModels>
          <Schema Namespace="MyDBModel.Store" Provider="System.Data.SqlClient" ProviderManifestToken="2012" 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="Users">
              <Key>
                <PropertyRef Name="Id" />
              </Key>
              <Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
              <Property Name="Name" Type="nvarchar" MaxLength="50" />
              <Property Name="Age" Type="int" />
            </EntityType>
            <EntityContainer Name="MyDBModelStoreContainer">
              <EntitySet Name="Users" EntityType="Self.Users" Schema="dbo" store:Type="Tables" />
            </EntityContainer>
          </Schema>
        </edmx:StorageModels>

    模型对象(ConceptualModels)

    它包含对象的信息(命名空间),主键(必须要设置),对象各属性的信息,对象容器

    <edmx:ConceptualModels>
          <Schema Namespace="MyDBModel" 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 Name="User">
              <Key>
                <PropertyRef Name="Id" />
              </Key>
              <Property Name="Id" Type="Int32" Nullable="false" annotation:StoreGeneratedPattern="Identity" />
              <Property Name="Name" Type="String" MaxLength="50" FixedLength="false" Unicode="true" />
              <Property Name="Age" Type="Int32" />
            </EntityType>
            <EntityContainer Name="MyDBEntities" annotation:LazyLoadingEnabled="true">
              <EntitySet Name="Users" EntityType="Self.User" />
            </EntityContainer>
          </Schema>
        </edmx:ConceptualModels>

    映射信息(Mappings)

    包含表信息的映射,和表中各字段的映射

    <edmx:Mappings>
          <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
            <EntityContainerMapping StorageEntityContainer="MyDBModelStoreContainer" CdmEntityContainer="MyDBEntities">
              <EntitySetMapping Name="Users">
                <EntityTypeMapping TypeName="MyDBModel.User">
                  <MappingFragment StoreEntitySet="Users">
                    <ScalarProperty Name="Id" ColumnName="Id" />
                    <ScalarProperty Name="Name" ColumnName="Name" />
                    <ScalarProperty Name="Age" ColumnName="Age" />
                  </MappingFragment>
                </EntityTypeMapping>
              </EntitySetMapping>
            </EntityContainerMapping>
          </Mapping>
        </edmx:Mappings>
      </edmx:Runtime>

    b.EF为我们复制了程序集

    这里用复制是因为,引进的程序集本身不在原生Framework中,它类似一个第三方开发包,在你添加实体程序时,会把该程序集复制到你所在项目中的package文件夹中

    #region 程序集 EntityFramework.dll, v6.0.0.0
    // E:ConsoleApplication1packagesEntityFramework.6.0.0lib et45EntityFramework.dll
    #endregion

    3.EF中的延迟加载

    先说下两个Where()方法

    a.集合的Where():

    image

    从上图可以得到信息:

    1.集合中的Where()方法是一个扩展方法

    2.该扩展方法是对接口IEnumerable的扩展,方法返回的是一个bool类型

    3.该方法在命名空间System.Linq下

    b.上下文中的Where()方法

    image

    从上图中可以得到信息

    1.上下文中的Where()有一个是对IQueryable的扩展
    2.命名空间也是在System.Linq下

    补充上面的Where()中的方法,设立断点,监视list1的数据类型,如下图

    image

    知道返回的类型是DBQuery

    通过查看定义,知道了延迟加载是基于System.Linq.Queryable给 IQueryable添加了扩展方法;而延迟加载真正是通过DbQuery实现的。

    c.为什么使用延迟加载

    原因一:当前可能通过多个SQO(标准查询)方法来组合查询条件【context.User.Order().Where().Select()】,而每个都只是添加一个查询条件,无法确定本次查询条件是否已经结束。所以,没有办法在每个SQO方法的时候确定SQL语句是什么,只能返回一个包含了所有添加的天剑的DBQuery对象,当使用这个DBQuery对象的时候,才根据所欲条件生成相应的Sql语句,查询数据

    原因二:针对于外键实体的延迟,对于外键属性而言。临时查询外键表 也叫延迟加载 用到了才去查,EF会用这个外键属性的时候才会去查对应的表,而不是一口气将外键全部查出来。

    MyBlogEntities context=new MyBlogEntities();
    //说明:表BlogArticlehe 和表BlogUser有个主外键关系 
    //查询文章表中IsDel为0的所有文章
    //虽然有外键表,但是没用到外键表,就不去查
    IQueryable<BlogArticle> existArticles = context.BlogArticles.Where(u => u.IsDel==false).Select(u => u);
    //从这些文章中 获得第一个文章
    BlogArticle blog01 = existArticles.FirstOrDefault();
    //获得这篇文章的作者信息 
    //通过sql profiler知道,直到执行这句话的时候,才查询表BlogUser
    //在ado.net中,会通过union直接将两张表联合起来查询,不管你需不需要外键表的数据
    //知道用到外键实体的时候,才会去查询外键表
    Console.WriteLine(blog01.BlogUser.LoginName);

    延迟加载有个缺点:

    //每次调用外键实体时,都会查询数据库(EF有小优化:相同的外键实体只查一次)
    IQueryable<BlogArticle> allArticles = context.BlogArticles.Select(u => u);
     foreach (BlogArticle article in allArticles)
      {
      //每次调用article.BlogUser.LoginName都会生成去查询数据库中的数据
      Console.WriteLine("文章名:"+article.Title+",文章作者:"+article.BlogUser.LoginName);
     }

    解决方法,使用Include将多个外键对象连接起来

    //通过Include方法,设置EF生成sql语句,使用inner join把用户表对应的LoginName也查出来
     //select * from BlogArticle b inner join Article a on b.Author=a.Id
     IQueryable<BlogArticle> allArticles = context.BlogArticles.Include("BlogArticleCate").Include("BlogUser");
      foreach (BlogArticle article in allArticles)
       {
      //一共就对数据进行了一次查询,将查询讲过保存到内存
     Console.WriteLine("文章名:" + article.Title + ",文章作者:" + article.BlogUser.LoginName);
       }
    更多精彩内容请看:http://www.cnblogs.com/2star
  • 相关阅读:
    Httpclient5工具类
    temp
    《On Java 8》笔记 2
    《On Java 8》笔记
    《Effective Java》笔记 4~5
    Oracle数据库对比MySQL
    《Effective Java》笔记
    [BUAA2021软工]结对第一阶段博客作业小结
    Spring Boot入门
    MyBatis入门
  • 原文地址:https://www.cnblogs.com/kimisme/p/4198565.html
Copyright © 2020-2023  润新知