LinqToDB框架是一个轻量级的ORM框架。当然,功能上来讲一定比不上Entity Framework的强大。但是在使用上总让笔者感觉有一点Entity Framework的影子。笔者想过可能的原因有俩点:一是DataContext类的作用跟DbContext的作用很接近;二是都实现Linq查询的功能。那么DataContext类到底在LinqToDB框架里面算什么呢?笔者把DataContext类理解为这个框架的上下文——用于驱动整个LinqToDB框架。所以本章也是为DataContext类而来。

框架配置


从源码里面我们可以看到DataContext类有三个构造函数。笔者也是根据这三个构造函数来推断出LinqToDB框架可存在多种启动方式。这里面最大的亮点不是构造函数而是他的参数名。如下代码。

public DataContext(): this(DataConnection.DefaultConfiguration);
public DataContext(string configurationString);
public DataContext(IDataProvider dataProvider,string connectionString);

上面代码有俩个参数名很重要——configurationString和connectionString。如果把他们都译过来的话,就是配置字符串和连接字符串。相信不难看出configurationString就是跟配置文件画上关系。而connectionString就是传入连接字符串的意思。本质来讲实现DataContext类只有俩种方式:一种是通过配置文件(如App.config)来实现;一种是用IDataProvider接口实例和连接字符串来实现。如果你什么也不传的话,就会使用默认的配置信息来实现。

LinqToDB框架根据.NET配置机制实现自定义配置。跟配置有关系的类都存放在LinqToDB.Configuration命名空间下。如果要实现.NET配置机制的话,就必须要有一个实现ConfigurationSection的类。LinqToDBSection类就是要我们要找的类了。作者用单例模式来设计LinqToDBSection类。相信大家都能明白作者的目地。那么LinqToDB框架是什么时候加载配置信息的呢?

注意:LinqToDBSection有俩个属性一个子点。DefaultConfiguration属性用于指定默认配置字符串。DefaultDataProvider属性用于指定默认数据提供者。还有叫dataProviders的子节点。关于dataProviders节点笔者希望大家不要去用。主要是笔者觉得作者这边写的有一点问题。当然有兴趣的朋友可以去看看。

LinqToDB框架启动本质上来讲就是实例化DataContext类成功了。从上面的三个构造函数我们可以看出在实例化DataContext类的时候,就必须传入一个配置字符串的参数。对于配置字符串来讲,你可以手动指定或是设置对应的配置信息。不管是哪一种最终都会去调用DataConnection类。哪怕你什么都不传的情况下,LinqToDB框架也会通过DataConnection.DefaultConfiguration来获得默认的配置字符串。笔者要讲的是就是这个时候开始加载配置信息。而这一切都将交给DataConnection类来负责。

 static DataConnection()
{
_configurationIDs = new ConcurrentDictionary<string, int>(); LinqToDB.DataProvider.SqlServer.SqlServerTools.GetDataProvider();
LinqToDB.DataProvider.Access.AccessTools.GetDataProvider();
LinqToDB.DataProvider.SqlCe.SqlCeTools.GetDataProvider();
LinqToDB.DataProvider.Firebird.FirebirdTools.GetDataProvider();
LinqToDB.DataProvider.MySql.MySqlTools.GetDataProvider();
LinqToDB.DataProvider.SQLite.SQLiteTools.GetDataProvider();
LinqToDB.DataProvider.Sybase.SybaseTools.GetDataProvider();
LinqToDB.DataProvider.Oracle.OracleTools.GetDataProvider();
LinqToDB.DataProvider.PostgreSQL.PostgreSQLTools.GetDataProvider();
LinqToDB.DataProvider.DB2.DB2Tools.GetDataProvider();
LinqToDB.DataProvider.Informix.InformixTools.GetDataProvider();
LinqToDB.DataProvider.SapHana.SapHanaTools.GetDataProvider(); var section = LinqToDBSection.Instance; if (section != null)
{
DefaultConfiguration = section.DefaultConfiguration;
DefaultDataProvider = section.DefaultDataProvider; foreach (DataProviderElement provider in section.DataProviders)
{
var dataProviderType = Type.GetType(provider.TypeName, true);
var providerInstance = (IDataProviderFactory)Activator.CreateInstance(dataProviderType); if (!string.IsNullOrEmpty(provider.Name))
AddDataProvider(provider.Name, providerInstance.GetDataProvider(provider.Attributes));
}
}
}

这是DataConnection类的静态构造构函数。我们可以看出他做了俩件事情:一是加载框架里面所有的数据提供者;二是加载配置文件上的信息。对于数据提供者下面会介绍啊。我们来看一下加载配置相关的内容。如下

1.设置默认的配置字符串和数据提供者名称
2.如果配置文件上存在数据提供者的话,就加载对应的数据提供者工厂(IDataProviderFactory)。然后通过工厂来获得数据提供者。

通过上面的了解,是不是说明在实例化DataContext类的时候,什么参数都不传的情况下,我们就一定要在配置文件里面指定默认的配置字符串呢?本来笔者以为如果你在配置文件不指定的话,LinqToDB框架就会报错误。可是让笔者傻眼的是完全没有问题。这又是什么一会事情呢?看一下笔者例子的源码吧。

配置代码:

 <?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="linq2db" type="LinqToDB.Configuration.LinqToDBSection, linq2db" requirePermission="false" />
</configSections>
<!--<linq2db defaultConfiguration="Aomi" />-->
<connectionStrings>
<add name="Aomi" connectionString="Data Source=.;Initial Catalog=Northwind;User ID=sa;Password=123" providerName="System.Data.SqlClient" />
</connectionStrings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>

上下文代码:

public class AdoContext : DataContext
{
public ITable<Products> Products
{
get
{
return this.GetTable<Products>();
}
}
}

例子中我们可以看到笔者配置了连接字符串却注解掉了指定的默认配置字符串。同时AdoContext类调用的是默认的构造函数。执行很成功。笔者却久久不能闭眼。为什么呢?事实上除了上面讲到的静态构造构函数(DataConnection类)里面会去设置默认配置字符串。作者又发神精的在另一个小小的地方也做了同样子的事情——InitConnectionStrings方法。

 static void InitConnectionStrings()
{
foreach (ConnectionStringSettings css in ConfigurationManager.ConnectionStrings)
{
_configurations[css.Name] = new ConfigurationInfo(css); if (DefaultConfiguration == null && !IsMachineConfig(css))
{
DefaultConfiguration = css.Name;
}
}
}

InitConnectionStrings方法是用于处理配置连接字符串。同时又多做了一件事情判断默认配置字符串是否存在。如果他不存在的话,就是连接字符串的Name给他。那么InitConnectionStrings方法也是在实例化DataContext类的时候进行的。详细如下。

到了这里相信对LinqToDB框架配置方面就有了一定的了解。有了配置信息,自然就知道去哪里找连接字符串。同时也就明白了去哪里查找数据库的信息。

数据供应者


在做Linq查询之前,对于数据库的信息,LinqToDB框架还是有必要知道的。作者充分的考虑过框架将来是要为多种数据库服务的。所以多出了一个角色叫数据提供者。不同的数据库就有相应的数据提供者。从设计的角度来讲可以说是提供者模式。所有的数据提供者类在LinqToDB.DataProvider命名空间下。他们有一个共同的基类叫IDataProvider接口。但是不是直接实现接口,而是继承DataProviderBase类。如图下。

数据供应者在Linq查询过程中,DataProvider起了举足轻重的作用。笔者先暂停介绍他的作用。让我们看看他是出自哪里的。从上面DataConnection类的静态构造构函数里面,我们会发现他加载配置信息的同时也会初始化框架里所有的数据提供者。为了方便笔者把初始化数据提供者部分的代码贴在下面。

LinqToDB.DataProvider.SqlServer.SqlServerTools.GetDataProvider();
LinqToDB.DataProvider.Access.AccessTools.GetDataProvider();
LinqToDB.DataProvider.SqlCe.SqlCeTools.GetDataProvider();
LinqToDB.DataProvider.Firebird.FirebirdTools.GetDataProvider();
LinqToDB.DataProvider.MySql.MySqlTools.GetDataProvider();
LinqToDB.DataProvider.SQLite.SQLiteTools.GetDataProvider();
LinqToDB.DataProvider.Sybase.SybaseTools.GetDataProvider();
LinqToDB.DataProvider.Oracle.OracleTools.GetDataProvider();
LinqToDB.DataProvider.PostgreSQL.PostgreSQLTools.GetDataProvider();
LinqToDB.DataProvider.DB2.DB2Tools.GetDataProvider();
LinqToDB.DataProvider.Informix.InformixTools.GetDataProvider();
LinqToDB.DataProvider.SapHana.SapHanaTools.GetDataProvider();

我们可以看到对应的每一个数据库都会一个相应的XxxTools类。XxxTools类里面包含了大量的静态方法。这个时候笔者又不得不把DataConnection类在拿出来讲。为什么呢?DataConnection类里面有一个叫_dataProviders的集合属性。他是静态的。主要用于存在当前拥有的数据提供者。所以上面这段代码初始化之后,所有的数据提供者都会存放在DataConnection类里面。

上面的代码执行完成之后,我们就拥有了所有的数据提供者。但最后LinqToDB框架还是会根据当前指定的配置字符串找到对应的数据提供者。这过程中会让一个叫ConfigurationInfo类来帮忙。ConfigurationInfo类就是用于存放从配置文件来的配置信息。ConfigurationInfo类里面有一个数据提供者属性DataProvider。通过这个属性我们就可以获得当前的数据库对应的数据提供者。还是笔者画来一张图片来形容这个过程吧。

注意:x.x.x 表示有三层,每一层按数字大小执行,相应数字后面的层必须先执行。比如有1.2和1.2.1就必须先把1.2.1执行完才能去执行1.2。又如1.1和1.2就是1.1执行完去执行1.2

DataContext类想要知道数据库的信息。就必须通过数据提供者来获得。所以就会在构造函数里面调用DataConnection类的GetDataProvider方法。但是这一步开始之前一定会先执行DataConnection类的静态构造函数。DataConnection类的静态构造函数里面又去调用所有XxxTools类的GetDataProvider方法。相应的又必须先调了XxxTools类的静态构造函数。相应的结果之后才会去执行DataConnection类的GetDataProvider方法。接下就看上面图片的。

当我们拿到了对应的数据提供者之后,DataContext类就是通过数据提供者获得相应的配置字符串、数据提供者的名称和结构映射。这些都是DataContext类的构造函数里面知道的。如果只是这么简单的话,那么笔者肯定不爽。事实上数据提供者还会参与后面的工作。让笔者先拿出一部分的代码来介绍一下数据提供者还有一些什么功能。

 /// <summary>
/// 数据供应者
/// </summary>
public interface IDataProvider
{
/// <summary>
/// 供应者的名称
/// </summary>
string Name { get; }
/// <summary>
/// 连接类的空间命名
/// </summary>
string ConnectionNamespace { get; }
/// <summary>
/// 对应DataReader类的类型
/// </summary>
Type DataReaderType { get; }
/// <summary>
/// 获得当前的结构映射
/// </summary>
MappingSchema MappingSchema { get; }
/// <summary>
/// 有一点像是标记数据库的状态
/// </summary>
SqlProviderFlags SqlProviderFlags { get; }
/// <summary>
/// 新建一个数据库连接
/// </summary>
/// <param name="connectionString"></param>
/// <returns></returns>
IDbConnection CreateConnection(string connectionString);
/// <summary>
/// 新建一个生成T-SQL的SQL生成类
/// </summary>
/// <returns></returns>
ISqlBuilder CreateSqlBuilder();
/// <summary>
/// 新建一个优化SQL的优化类
/// </summary>
/// <returns></returns>
ISqlOptimizer GetSqlOptimizer();
/// <summary>
/// 初始化一个Command命令。Command就是如SqlCommand之类的。
/// </summary>
/// <param name="dataConnection"></param>
/// <param name="commandType"></param>
/// <param name="commandText"></param>
/// <param name="parameters"></param>
void InitCommand(DataConnection dataConnection, CommandType commandType, string commandText, DataParameter[] parameters);
/// <summary>
/// 删除一个Command命令
/// </summary>
/// <param name="dataConnection"></param>
void DisposeCommand(DataConnection dataConnection); //.....
//.....
//.....
//..... }

最后一定会去执行数据库,那么获得数据库连接是肯定有的。所以我们可以从上面看到新建一个数据库连接的功能。同时数据提供者又带有新建生成T-SQL的功能类。笔者上面有提到结构映射(MappingSchema类)这个功能类。他的作用就是帮我们决定语言之间的类型问题。必竟C#和SQL类型上还是有一定的差别的。每执行一个T-SQL语句相应的会有一个Command命令。这一部分的工作也是有数据提供者的职责。看样子数据提供者真的很忙。

我们先大体上的了解一个数据提供者的作用。因为本章主要是DataContext类相关的知道点。而且关于数据提供者还有要结合后面的代码功能才能更加深入的了解。所以本章对应数据提供者就讲到这里。

结束语


DataContext类源码里面还包含了一些对数据库操作的方法,我们会发现他本身好像拥有对数据库增删改的功能。可是笔者并没有在本章中介绍到,这并不意味着结束。事实上DataContext类都在后面的章节出动不动的出显。所以相应的关于DataContext类的作用也会跟着介绍出来。

LinqToDB 源码分析——DataContext类的更多相关文章

  1. LinqToDB 源码分析——生成表达式树

    当我们知道了Linq查询要用到的数据库信息之后.接下就是生成对应的表达式树.在前面的章节里面笔者就已经介绍过.生成表达式树是事实离不开IQueryable<T>接口.而处理表达式树离不开I ...

  2. LinqToDB 源码分析——前言

    记得笔者进入公司的时候接触的第一个ORM框架是Entity Framework.为了Entity Framework也看了不些的英文资料(不是笔者装B哦).正式使用三个月后.笔者对他有一个全面性的认识 ...

  3. Struts2 源码分析——DefaultActionInvocation类的执行action

    本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...

  4. Struts2 源码分析——Result类实例

    本章简言 上一章笔者讲到关于DefaultActionInvocation类执行action的相关知识.我们清楚的知道在执行action类实例之后会相关处理返回的结果.而这章笔者将对处理结果相关的内容 ...

  5. LinqToDB 源码分析——生成与执行SQL语句

    生成SQL语句的功能可以算是LinqToDB框架的最后一步.从上一章中我们可以知道处理完表达式树之后,相关生成SQL信息会被保存在一个叫SelectQuery类的实例.有了这个实例我们就可以生成对应的 ...

  6. LinqToDB 源码分析——设计原理

    我们知道实现了IQueryable<T>接口和IQueryProvider接口就可以使用Linq To SQL的功能.关于如何去实现的话,上一章也为我们引导了一个方向.LinqToDB框架 ...

  7. tornado框架源码分析---Application类之debug参数

    先贴上Application这个类的源码. class Application(httputil.HTTPServerConnectionDelegate): """A ...

  8. LinqToDB 源码分析——处理表达式树

    处理表达式树可以说是所有要实现Linq To SQL的重点,同时他也是难点.笔者看完作者在LinqToDB框架里面对于这一部分的设计之后,心里有一点不知所然.由于很多代码没有文字注解.所以笔者只能接合 ...

  9. LinqToDB 源码分析——轻谈Linq查询

    LinqToDB框架最大的优势应该是实现了对Linq的支持.如果少了这一个功能相信他在使用上的快感会少了一个层次.本来笔者想要直接讲解LinqToDB框架是如何实现对Linq的支持.写到一半的时候却发 ...

随机推荐

  1. 【翻译】MongoDB指南/聚合——聚合管道

    [原文地址]https://docs.mongodb.com/manual/ 聚合 聚合操作处理数据记录并返回计算后的结果.聚合操作将多个文档分组,并能对已分组的数据执行一系列操作而返回单一结果.Mo ...

  2. JavaScript Object对象

    目录 1. 介绍:阐述 Object 对象. 2. 构造函数:介绍 Object 对象的构造函数. 3. 实例属性:介绍 Object 对象的实例属性:prototype.constructor等等. ...

  3. 前端学HTTP之日志记录

    前面的话 几乎所有的服务器和代理都会记录下它们所处理的HTTP事务摘要.这么做出于一系列的原因:跟踪使用情况.安全性.计费.错误检测等等.本文将谥介绍日志记录 记录内容 大多数情况下,日志的记录出于两 ...

  4. AFNetworking 3.0 源码解读 总结(干货)(上)

    养成记笔记的习惯,对于一个软件工程师来说,我觉得很重要.记得在知乎上看到过一个问题,说是人类最大的缺点是什么?我个人觉得记忆算是一个缺点.它就像时间一样,会自己消散. 前言 终于写完了 AFNetwo ...

  5. AFNetworking 3.0 源码解读(九)之 AFNetworkActivityIndicatorManager

    让我们的APP像艺术品一样优雅,开发工程师更像是一名匠人,不仅需要精湛的技艺,而且要有一颗匠心. 前言 AFNetworkActivityIndicatorManager 是对状态栏中网络激活那个小控 ...

  6. js闭包 和 prototype

    function test(){ var p=200; function q(){ return p++; } return q; } var s = test(); alert(s()); aler ...

  7. Android使用静默安装时碰见的问题

    升级时碰见的异常 private void installPackage(String appName,final File apk) { if (!apk.exists()) { setHasNew ...

  8. .Net 初步学习笔记之一——.Net 平台与.Net FrameWork框架的关系

    .Net 包含两部分 .Net平台 和.Net FrameWork 框架 1..Net FrameWork框架包含于.Net平台. .Net FrameWork提供环境和支撑保证.Net平台运行. 2 ...

  9. ubuntu14 查找并删除所有文件名中带有特定关键词的文件

    http://askubuntu.com/questions/625219/how-to-search-and-delete-files-who-contain-specific-string-in- ...

  10. Lesson 24 It could be worse

    Text I entered the hotel manager's office and sat down. I had just lost £50 and I felt very upset. ' ...