EF怎样实现ORM思想的(转载)

时间:2022-09-12 16:21:52

EF简介

实体框架(Entity Framework)简称EF,是微软以ADO.NET为基础所发展出来的对象关系对应(O/R Mapping)解决方案。是ADO.NET中的一组支持开发面向数据的软件应用程序的技术。是微软的一个ORM框架。

ORM

O/R Mapping 是EF中非常重要的一个思想,官方解释为:ORM指的是面向对象的对象模型和关系型数据库的结构之间的相互转换。

通俗的讲,ORM就是将表实体的变化映射到一个表。

EF原理图解

通过ORM思想的指导,Entity Framework就可以帮助开发人员跟踪实体的变化,将实体的变化翻译成SQL脚本,并执行到数据中去,也就是将实体的变化映射到了表的变化。

1)体系结构图

EF怎样实现ORM思想的(转载)

linq语句赋值给一个var 变量,类型为IQueryable。

命令树就是IQueryable接口中的树状表达式Express,就是说linq查询语句转变成为树状表达式。 最后EntityClient数据提供程序结合树状表达式和映射关系,调用底层ADO.Net数据提供程序生成sql语句。

2)组件图

EF怎样实现ORM思想的(转载)

根据上图可知,EF可以跨数据库(mySql、Oracle 等),需要先安装相关驱动,然后更改配置文件连接字符串Provider名称。

官网链接

https://docs.microsoft.com/zh-cn/previous-versions/visualstudio/visual-studio-2008/bb896338(v%3dvs.90)

https://msdn.microsoft.com/zh-cn/library/bb358362(v=VS.90).aspx

------------------------------------------------------------------

EntityFramework之摸索EF底层(八)

前言

此篇文章我将深入去摸索edmx中一些不为人知的东西,有时候我们需要知道Code  First模型中一些存储以及映射的原理,个人觉得那是必要的也是有用的,因为很有可能SQL会出现一些其他问题,只有掌握了一些必备的原理,这样当报错时才会不知所措。

原理

我们知道实体数据模型(EDM)是应用程序和数据存储之间的沟通桥梁,同时我们通过属性映射的API与数据存储之间的交互都是基于EDX,所以一切我们从EDM开始谈起。

我们不用操之过急,我们先了解原理之后,再通过实际来操作你就明白为什么要先了解原理的至关重要性了(可能会有点枯燥,but please take it easy!)。

先给出数据库表对应的类(下面会用到):

EF怎样实现ORM思想的(转载)
    public partial class Student
{
public int Key { get; set; }
public string Name { get; set; }
public int FlowerId { get; set; } public virtual Flower Flower { get; set; }
}
EF怎样实现ORM思想的(转载)
EF怎样实现ORM思想的(转载)
    public partial class Flower
{
public Flower()
{
this.Students = new HashSet<Student>();
} public int Id { get; set; }
public string Remark { get; set; }
public virtual ICollection<Student> Students { get; set; }
}
EF怎样实现ORM思想的(转载)

下面我们一步步来进行,我们新建一个ADO.NET实体数据模型,如下:

EF怎样实现ORM思想的(转载)

因为之前用的Code->Database,现在我们反其道为之,通过Database->Code来获得生成的设计架构,于是我们需要来自数据库的EF设计器,如下:

EF怎样实现ORM思想的(转载)

生成了基本的架构之后,我们看到了最重要的edmx,也就是EDM中的XML文件,但是此时看到的只是类图,我们需要通过指定XML工具来打开如下:

EF怎样实现ORM思想的(转载)

此时你将清楚的看到edmx中架构:

EF怎样实现ORM思想的(转载)

里面最重要的就是这三部分,不用说大家也能明白:概念模型定义语言(CSDL)即概念层、存储模型定义语言(SSDL)即存储层、概念与存储之间的映射语言(MSL)即映射层。

接下来我们就存储模型具体来看看里面到底有什么东西,我们看几个重要的部分:

EntityContainer和EntitySet

EF怎样实现ORM思想的(转载)
        <EntityContainer Name="DBByConnectionStringModelStoreContainer">
<EntitySet Name="Flower" EntityType="Self.Flower" Schema="dbo" store:Type="Tables" />
<EntitySet Name="Student" EntityType="Self.Student" Schema="dbo" store:Type="Tables" />
<AssociationSet Name="FK_dbo_Student_dbo_Flower_FlowerId" Association="Self.FK_dbo_Student_dbo_Flower_FlowerId">
<End Role="Flower" EntitySet="Flower" />
<End Role="Student" EntitySet="Student" />
</AssociationSet>
</EntityContainer>
EF怎样实现ORM思想的(转载)

由上我们知道:EntityContainer容器的名称是由数据库名称+ModelStoreContainer,并且它是 EntitySet 和 AssociationSet 的容器,而EntityContainer的作用是查询的重要入口,通过暴露EntitySet,来使得我们查询到EntitySet,而EntitySet是实体的集合,所以通过它访问到实体。

EntityType

EF怎样实现ORM思想的(转载)
        <EntityType Name="Flower">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Remark" Type="nvarchar(max)" />
</EntityType>
<EntityType Name="Student">
<Key>
<PropertyRef Name="Key" />
</Key>
<Property Name="Key" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
<Property Name="Name" Type="nvarchar(max)" />
<Property Name="FlowerId" Type="int" Nullable="false" />
</EntityType>
EF怎样实现ORM思想的(转载)

实体类型是模型中的数据类型,我们可以看到里面有我们定义的Flower和Student类,并在其节点下列出了其所有属性。

C-S Mapping

EF怎样实现ORM思想的(转载)
    <edmx:Mappings>
<Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">
<EntityContainerMapping StorageEntityContainer="DBByConnectionStringModelStoreContainer" CdmEntityContainer="DBByConnectionStringEntities">
<EntitySetMapping Name="Flowers">
<EntityTypeMapping TypeName="DBByConnectionStringModel.Flower">
<MappingFragment StoreEntitySet="Flower">
<ScalarProperty Name="Id" ColumnName="Id" />
<ScalarProperty Name="Remark" ColumnName="Remark" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
<EntitySetMapping Name="Students">
<EntityTypeMapping TypeName="DBByConnectionStringModel.Student">
<MappingFragment StoreEntitySet="Student">
<ScalarProperty Name="Key" ColumnName="Key" />
<ScalarProperty Name="Name" ColumnName="Name" />
<ScalarProperty Name="FlowerId" ColumnName="FlowerId" />
</MappingFragment>
</EntityTypeMapping>
</EntitySetMapping>
</EntityContainerMapping>
</Mapping>
</edmx:Mappings>
EF怎样实现ORM思想的(转载)

上述EntityContainerMapping中的StorageEntityContainer(存储实体容器)对应存储模型中EntityContainer中的Name,而EntitySetMapping下的EntityTypeMapping中的TypeName则对应概念模型的中EntityType下的Name。也就是说通过StorageEntityContainer来获得存储模型中EntityContainer,接着根据下面EntityType对应的值去获得概念模型中对应的实体,此时映射层中用TypeName来获得概念模型中的实体,接着开始进行一一对应映射,此时MappingFragment(就字面意思暂且叫映射片段),将名称为Name的值映射为对应的列名ColumnName的值。上述大概就是整个映射过程。

这就是我简短的介绍,更多详细内容请参考园友三思而后行翻译的早期EF系列。下面进入实战。

实战

在进入之前,我们先得了解 DataSpace 枚举中的几个概念:

  • CSpace:概念模型的默认名称。
  • CSSpace:概念模型和存储模型之间的映射的默认名称。
  • OCSpace:对象模型和概念模型之间的映射的默认名称。
  • OSpace:对象模型的默认名称。
  • SSpace:存储模型的默认名称。

在EF中我们是无法用DbContext上下文来直接获得表名以及各种属性等等,但是对于这所有我们可以通过上下文ObjectContext中的MetadataWrokSpace属性来操作,因为该属性暴露了GetItems方法来使我们很容易获得我们想要的数据。

那问题来了,如果我们要获得实体的所有键的名称,该如何操作呢?

我们通过给上下文添加一个扩展方法 GetKeyNames 来获取实体所有的键名称,如下:

EF怎样实现ORM思想的(转载)
        static string[] GetKeyNames(this DbContext ctx, Type entity)
{
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace; /*获得CLR type集合和medata OSpace之间的映射*/
var objItemCollection = (ObjectItemCollection)metadata.GetItemCollection(DataSpace.OSpace); /*根据所给的CLR type获得实体的元数据即metadata*/
var entitydata = metadata.GetItems<EntityType>(DataSpace.OSpace).Single(e => objItemCollection.GetClrType(e) == entity);
/*返回实体的所有键的集合*/
return entitydata.KeyProperties.Select(p => p.Name).ToArray(); }
EF怎样实现ORM思想的(转载)

接下来我们调用如下就获得该实体对应的所有键的集合

 var keyNames = ctx.GetKeyNames(typeof(Student));

通过上述想必你也明白了为什么要讲 EntityType、EntityContainer以及EntitySet 了吧。我们不禁猜想如果要获得CLR types与存储模型之间的映射的集合应该如何操作呢?显然,如下:

var storeItemCollection = (StoreItemCollection)metadata.GetItemCollection(DataSpace.SSpace);

我们查看我们通过映射获得数据库表Flower和Student的情况如下:

EF怎样实现ORM思想的(转载)

那问题又来了,我们该如何获得实体对应的表名呢?

通过上述原理的介绍,既然是表名肯定此时DataSpace枚举必须是存储模型即SSpace,同时我们要获得EntitySet集合中对应的Name,同时表名我们知道默认是dbo,即上述Schema对应的值再加上Table所对应的值,基于此,我们尝试写出相应的代码:

EF怎样实现ORM思想的(转载)
        static string GetTableName(this DbContext ctx, Type entity)
{
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace; var storeItemCollection = metadata.GetItemCollection(DataSpace.SSpace); var entitySetBase = storeItemCollection.GetItems<EntityContainer>().Single().BaseEntitySets.Where(e => e.Name == entity.Name).Single(); string tableName = entitySetBase.MetadataProperties["Schema"].Value + "." + entitySetBase.MetadataProperties["Table"].Value; return tableName;
}
EF怎样实现ORM思想的(转载)

上述代码就不一一解释了,对照edmx就很清楚了,接下来我们进行测试来获得Student的表名:

var tableName = ctx.GetTableName(typeof(Student));

测试通过,如下:

EF怎样实现ORM思想的(转载)

那问题又来了,我们该如何获得实体的所有导航属性呢?

既然是实体的导航属性必定是要在获取到实体的前提下再去获取导航属性,主要通过此 metadata.GetItems(DataSpace.OSpace) 来筛选出实体类型最后查到需要一个内置类型种类 BuiltInTypeKind 。所以我们给出完整代码:

EF怎样实现ORM思想的(转载)
        static IEnumerable<PropertyInfo> GetNavigationPrpoperties(this DbContext ctx, Type entity)
{
var metadata = ((IObjectContextAdapter)ctx).ObjectContext.MetadataWorkspace; var entityType = metadata.GetItems(DataSpace.OSpace).Where(d => d.BuiltInTypeKind == BuiltInTypeKind.EntityType).OfType<EntityType>().Where(d => d.Name == entity.Name).Single(); return (entityType.NavigationProperties.Select(d => entity.GetProperty(d.Name)).ToList()); }
EF怎样实现ORM思想的(转载)

我们依然进行调用,试试能否取到:

var navigationProperties = ctx.GetNavigationPrpoperties(typeof(Student));

结果成功取到Student的导航属性Flower,如下:

EF怎样实现ORM思想的(转载)

总结

上述也就简单的摸索了下底层为edmx的EF,个人感觉了解了基本原理再去写代码以及当代码出现问题时去解决会得心应手,同时了解这些基本原理对于我们在EF实体框架上构建建模工具也是非常有帮助的。

-------------------------------------------------------------------------

个人(hao_1234_1234)感觉转换成sql脚本的过程还与 IQueryable 和IEnumable 这两个接口有着密切的关系,但目前还不在如何查证,特此附上

       //linq 表达式的返回值的类型是IQueryable
IQueryable<HKSJ_USERS> temp = from u in dbContext.HKSJ_USERS
where u.ID >
select u;
//初始化了一下IQueryable接口里面的三个参数作用:
// 1 linq表达式转成表达式树Expression
// 2 给元素类型 Type ElementType赋值,这里指的是<HKSJ_USERS>
// 3 给提供者IQueryProvider Provider赋值,这里是efProvider,若是XML那就是xmlProvider,若是string 就stringProvider
         所以理论上linq可以无限扩展。 //当用到 IQueryable接口的集合的数据的时候,provider解析Expression然后获取相应的数据。进行遍历执行。
//linq to ef:查询是在数据库端进行过滤。
foreach (var hksjUsers in temp)
{
Console.WriteLine(hksjUsers.ID + " " + hksjUsers.UserName);
} //IEnumable内存里面过滤:把数据库中的所有的数据都查询到程序里面来之后,再进行过滤。
//linq to object
var demoList = from u in dbContext.HKSJ_USERS.AsIEnumable() //ToList()
where u.ID >
select u;
foreach (var hksjUsers in demoList)
{ }
       
//List集合、Arrary,Dictionary,....都继承与IEnumable接口。

IQueryable接口(F12查看)

namespace System.Linq
{
public interface IQueryable : IEnumerable
{
Type ElementType { get; }
Expression Expression { get; }
IQueryProvider Provider { get; }
}
}

IEnumerable接口(F12查看)

namespace System.Collections
{
//
// 摘要:
// Exposes an enumerator, which supports a simple iteration over a non-generic collection.To
// browse the .NET Framework source code for this type, see the Reference Source.
[ComVisible(true)]
[Guid("496B0ABE-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerable
{
//
// 摘要:
// Returns an enumerator that iterates through a collection.
//
// 返回结果:
// An System.Collections.IEnumerator object that can be used to iterate through
// the collection.
[DispId(-4)]
IEnumerator GetEnumerator();
}
}
namespace System.Collections
{
//
// 摘要:
// Supports a simple iteration over a non-generic collection.
[ComVisible(true)]
[Guid("496B0ABF-CDEE-11d3-88E8-00902754C43A")]
public interface IEnumerator
{
//
// 摘要:
// Gets the current element in the collection.
//
// 返回结果:
// The current element in the collection.
object Current { get; } //
// 摘要:
// Advances the enumerator to the next element of the collection.
//
// 返回结果:
// true if the enumerator was successfully advanced to the next element; false if
// the enumerator has passed the end of the collection.
//
// 异常:
// T:System.InvalidOperationException:
// The collection was modified after the enumerator was created.
bool MoveNext();
//
// 摘要:
// Sets the enumerator to its initial position, which is before the first element
// in the collection.
//
// 异常:
// T:System.InvalidOperationException:
// The collection was modified after the enumerator was created.
void Reset();
}
}

来源:

https://www.cnblogs.com/CreateMyself/p/4783027.html   (此人有更多好文,值得细看)

https://blog.csdn.net/yiwangxiblog/article/details/51471314

EF怎样实现ORM思想的(转载)的更多相关文章

  1. ORM思想解析

    ORM思想解析 qq_16055765 2019-01-10 11:29:08 1688 收藏 1 分类专栏: # hibernate 最后发布:2019-01-10 11:29:08首次发布:201 ...

  2. easyui datagrid 禁止选中行 EF的增删改查(转载) C&num; 获取用户IP地址(转载) MVC EF 执行SQL语句(转载) 在EF中执行SQL语句(转载) EF中使用SQL语句或存储过程 &period;net MVC使用Session验证用户登录 PowerDesigner 参照完整性约束&lpar;转载&rpar;

    easyui datagrid 禁止选中行   没有找到可以直接禁止的属性,但是找到两个间接禁止的方式. 方式一: //onClickRow: function (rowIndex, rowData) ...

  3. 【EF 4】ORM框架及其流行产品之一EF介绍

    导读:跳进了多租户切换数据库的坑,那么就继续走下去吧.在我们的项目中,是运用EF实现对数据库的操作,那么EF其实是.NET系统中,基于ORM框架的一个产品实现.在java那边,则有Hibernate和 ...

  4. 什么是orm思想?

    什么是orm思想? 1.hibernate使用orm思想对数据库进行crud操作 2.在web阶段学习javabean更正确的叫法是:实体类 3.orm: object   relational   ...

  5. ORM思想

    -------------------siwuxie095 什么是 ORM 思想 1.Hibernate 使用 ORM 思想对数据库进行 CRUD 操作 2.ORM:Object Relational ...

  6. 12 Spring Data JPA:orm思想和hibernate以及jpa的概述和jpa的基本操作

    spring data jpa day1:orm思想和hibernate以及jpa的概述和jpa的基本操作 day2:springdatajpa的运行原理以及基本操作 day3:多表操作,复杂查询 d ...

  7. 类EF框架Chloe&period;ORM升级:只为更完美

    扯淡 Chloe.ORM:一款轻量.高效的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq(但不支持 Linq).借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接 ...

  8. 第二篇:操纵MySQL数据库&lpar;2&rpar; - 基于ORM思想的SQLAlchemy库

    前言 本文讲解在Python语言中使用SQLAlchemy库操纵MySQL数据库的方法. 由于具体内容涉及较多,本文仅以插入及展示数据为例,更多内容请查阅有关文档. ORM ORM也即对象 - 关系映 ...

  9. 在EF中执行SQL语句(转载)

    在EF中执行SQL语句   你可能要问,我用EF不就为了避免写SQL吗?如果要写SQL我不如直接用ADO.NET得了.话虽然这么说没错,可有些时候使用EF操作数据还是有一些不方便,例如让你根据条件删除 ...

随机推荐

  1. Remove Duplicates from Sorted List II 解答

    Question Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only dist ...

  2. Java 二次MD5 32位小写加密算法与php页面加密结果相同

    最近做的一个项目需要使用MD5加密算法,需要加密的参数有两个.自己先试了几次,算的结果为php页面的不一样,后来与写php页面的同事沟通后,了解到php页面的算法如下: action = " ...

  3. HDU - 4995 - Revenge of kNN

    题目链接 : https://vjudge.net/problem/HDU-4995 题目大意  :   读入n个点的坐标与该点所拥有的值val,进行m次查询,对于每一次查询,读入该点的坐标,计算离该 ...

  4. PHP设计模式之工厂模式

    工厂模式(Factory pattern)和单例模式一样,是另外一种创建型模式. 和单例模式不同的是,单例模式会创建和管理一个单独的类型的单一对象,工厂模式则是用于创建多种不同类型的类的多个对象. 工 ...

  5. 【好用的Mac分屏软件】Magnet for Mac 2&period;3

      「Magnet」是一款Mac窗口管理工具. 当您每次将内容从一个应用移动到另一应用时,当您需要并排比较数据时,或是以其他方式进行多任务处理时,你需要妥善放置所有窗口.Magnet 让这一过程清爽又 ...

  6. PHP开发者的Linux学习之路

    谈起一个高效动态网站的构建,那就不得不提到LAMP,即Linux操作系统.Apache网络服务器.Mysql数据库.Perl.PHP或Python编程语言等开源产品所组成的网站架构框架,其最大的优势是 ...

  7. DG搭建方式区分

    DG搭建三种方式: 一.异机恢复,restore database,recover database 二. duplicate target database for standby from act ...

  8. Jmeter遇到线程链接被重置(Connection reset by peer&colon; socket write error)的解决方法

    做性能测试的时候遇到一个很奇怪的问题,多线程的计划,有一个线程第一次能跑过,第二次确跑不过,单独跑这个线程跑多少次都没有问题,把思考时间改短也没有问题,唯独出现在特定的状态下,特定状态是啥,也不得而知 ...

  9. plupload分片上传视频文件源码展示

    plupload分片上传视频文件目录结构如下: |- images//视频上传小图片 |-js// plupload js文件 |-uploads//视频文件存放文件夹 里面是按日期存放 |-ajax ...

  10. CodeForces Round &num;527 &lpar;Div3&rpar; D2&period; Great Vova Wall &lpar;Version 2&rpar;

    http://codeforces.com/contest/1092/problem/D2 Vova's family is building the Great Vova Wall (named b ...