前文说到如果使用多数据库(不同SQL方言)时要如何开发?其实前文(第二篇)也有“透露”到。就是直接使用库提供的OrmLiteConnectionOrmLiteConnectionFactory(IDbConnectionFactory) 。我们先来看下代理类是怎么实现的:

public class OrmLiteConnection : IDbConnection, IHasDbConnection, IHasDbTransaction
{
public readonly OrmLiteConnectionFactory Factory;
public IDbTransaction Transaction { get; set; }
private IDbConnection dbConnection;
private bool isOpen; public OrmLiteConnection(OrmLiteConnectionFactory factory)
{
this.Factory = factory;
} public IDbConnection DbConnection
{
get
{
if (dbConnection == null)
{
dbConnection = Factory.ConnectionString.ToDbConnection(Factory.DialectProvider);
}
return dbConnection;
}
}
} public interface IDbConnectionFactory
{
IDbConnection CreateDbConnection();
IDbConnection OpenDbConnection();
} public class OrmLiteConnectionFactory : IDbConnectionFactory
{
public OrmLiteConnectionFactory(): this(null, null, true) {}
public OrmLiteConnectionFactory(string connectionString) : this(connectionString, null, true) {}
public OrmLiteConnectionFactory(string connectionString, IOrmLiteDialectProvider dialectProvider)
: this(connectionString, dialectProvider, true) {} public OrmLiteConnectionFactory(string connectionString, IOrmLiteDialectProvider dialectProvider, bool setGlobalDialectProvider)
{
ConnectionString = connectionString;
AutoDisposeConnection = connectionString != ":memory:";
this.DialectProvider = dialectProvider ?? OrmLiteConfig.DialectProvider;
if (setGlobalDialectProvider && dialectProvider != null)
{
OrmLiteConfig.DialectProvider = dialectProvider;
}
this.ConnectionFilter = x => x;
}
public IOrmLiteDialectProvider DialectProvider { get; set; }
}

在OrmLite中OrmLiteConnection 可是一等公民,如果需要使用IDbConnectionFactory.DialectProvider ,而又想要通过代理实现各种功能的话,只能使用OrmLiteConnection 代理它,而它不能代理OrmLiteConnection 。如果需要代理原始连接,则可以使用OrmLiteConnectionFactory.ConnectionFilter

factory.ConnectionFilter = x =>new ProxyConnection(x);

因为前文提到了连接池,我就想应该如何使用IDbConnectionFactory来实现连接池(各位暂且不要先吐槽,等下我自行打面)。

虽然有OrmLiteConnectionFactory.ConnectionFilter的存在,但是且看OrmLiteConnection 是怎么使用代理连接的:

public IDbConnection DbConnection
{
get
{
if (dbConnection == null)
{
dbConnection = Factory.ConnectionString.ToDbConnection(Factory.DialectProvider); //(2)
}
return dbConnection;
}
} public void Dispose()
{
if (Factory.OnDispose != null) Factory.OnDispose(this);
if (!Factory.AutoDisposeConnection) return;
DbConnection.Dispose();
dbConnection = null;
isOpen = false;
} public void Open()
{
if (isOpen) return;
DbConnection.Open(); //(1)
if(Factory.ConnectionFilter != null)
{
dbConnection = Factory.ConnectionFilter(dbConnection);
}
isOpen = true;
}

先看看Open方法,其内部调用DbConnection.Open()(注释1),而初始dbConnection为null,则需要获取新连接(注释2)。以我的理解,我最初以为是通过IDbConnectionFactory.OpenDbConnection()获取新连接的,这样的话做代理就方便多啦!但是注释2中可是直接通过API创建新连接啊,也就是说,就算我可以做到连接的回收,也无法控制“产出”。
后来就请教了一个比较熟悉.Net的同学(有无用过OrmLite.IDbConnectionFactory,下一步是问他怎样实现连接池),他还没回复,我就恍然大悟的知道了要实现连接池不应该通过修改IDbConnectionFactory,而是通过代理IOrmLiteDialectProvider !这样的话就不需要修改Factory便可以控制连接的回收和产出!

而最初迷惑我使用OrmLiteConnectionFactory和OrmLiteConnection配合来实现代理的,正正是两者的例子。
首先,通过OrmLiteConnectionFactory.ConnectionFilter 创建代理。
其次,通过OrmLiteConnectionFactory.OnDispose 进行回收。
最后,OrmLiteConnectionFactory.OrmLiteConnection 的实现使我越陷越深,如果OrmLiteConnectionFactory作为工具类,那么OrmLiteConnection 属性是不应该存在的,而是由继承者实现。如果是用于测试,那只能说这样太不专业了,还有其源码注释也说明了:

/// <summary>
/// Allow for mocking and unit testing by providing non-disposing
/// connection factory with injectable IDbCommand and IDbTransaction proxies
/// </summary>
public class OrmLiteConnectionFactory : IDbConnectionFactory
{
}

说实话当时我都看醉了,要使用OrmLiteConnection不能配合IDbConnectionFactory使用,而必须通过其实现类OrmLiteConnectionFactory ,但OrmLiteConnectionFactory 的接口又不写成virtual,在不修改源码的情况下,是无法通过OrmLiteConnection(Factory)来实现连接池的(知道代理IOrmLiteDialectProvider 之前)。

而当我多么痛的领悟到要代理IOrmLiteDialectProvider 来实现连接池后,高兴地告诉了我请教那位同学。他告诉我:
ADO.NET!默!认!带!连!接!池!

我先是五雷轰顶,然后默默细想:印象中带连接池的是SqlConnection,那是SqlServer的东西吧?我用的可是Sqlite和MySql哦!最后我说明早再找资料看看(也就是今早)

(我没研究过ADO.NET什么的,我就是个偏科的程序员....)

后来我查了ADO的相关资料,说ADO.NET规范是默认支持连接池的,而且是默认开启。也就是说,无论是SqlServer还是Sqlite,想要实现ADO.NET那就得遵守它的规范咯!但是作为一看不看源码不安心行人,还是默默地拿起Reflector反编译了Sqlite.DLL:

internal static class SqliteConnectionPool
{
// Fields
private static SortedList<string, Pool> _connections;
private static int _poolVersion;
//...
}

果真是有。

<完>

再提一下,OrmLite不想Hibernate那样可以在对象里存对象然后直接存储ID这么智能,最多只能作为DTO的语言实现,否则OrmLite会直接将整个对象序列化到其中一个字段当中,还是看代码吧:

    public class Hello
{
[PrimaryKey]
[AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public World World { get; set; } //改为int WordId吧。
public Hello(string name, World w)
{
Name = name;
World = w;
}
}
public class World
{
[PrimaryKey]
[AutoIncrement]
public int Id { get; set; }
public string Address { get; set; }
public World(string addr)
{ Address = addr; }
}

总结:说到底这其实不算坑,这就是我瞎折腾。告诫各位还是先学好基础把文档看细为妙。

ServiceStack.OrmLite中的一些"陷阱"(3)的更多相关文章

  1. ServiceStack.OrmLite中的一些"陷阱"(2)

    注:此系列不是说ServiceStack.OrmLite的多个陷阱,这仅仅个人认为是某一个陷阱(毕竟我踩坑了)而引发的思考. 前文说到了项目需要使用两种不同的数据库语言,虽说前文问题已基本解决了,但是 ...

  2. ServiceStack.OrmLite中的一些"陷阱"(1)

    使用过ServiceStack.Ormlite的人都应该知道,其作为一个轻量级的ORM,使用的便捷度非常高,用起来就一个字:爽!而支撑其便捷度的,是库内大量地使用了扩展方法及静态变量. 首先先从源头入 ...

  3. ServiceStack.OrmLite 调用存储过程

    最近在做关于ServiceStack.OrmLite调用存储过程时,有问题.发现ServiceStack.OrmLite不能调用存储过程,或者说不能实现我想要的需求.在做分页查询时,我需要传入参数传出 ...

  4. ServiceStack.OrmLite

    ServiceStack.OrmLite 谈谈我的入门级实体框架Loogn.OrmLite   每次看到有新的ORM的时候,我总会留意一下,因为自己也写过一个这样的框架,人总是有比较之心的.我可能会d ...

  5. ServiceStack.OrmLite T4模板使用记录

    前言 最近研究了下ServiceStack.OrmLite,文档中也提到了使用T4模板对数据库中已经有了表进行实体的映射,这里也顺便记录下使用的步骤和情况. 开始使用 引用T4模板 首先我们创建一个工 ...

  6. ServiceStack.OrmLite 入门(一)

    软件环境: Win7 x64 SP1 SQL Server 2008r2 Visual Studio 2017 Professional 目标:取出示例数据库 ReportServer 的表 Role ...

  7. JavaScript中的this陷阱的最全收集 没有之一

    当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概 念,可能真解释不清楚.有句话这么说:如果你不能向一个6岁小孩解 ...

  8. 转:JavaScript中的this陷阱的最全收集

    在其他地方看到的,觉得解释的狠详细,特此分享 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清 ...

  9. ServiceStack.OrmLite 学习笔记7-复杂点的使用1

    复杂点的使用1 先看看这2个类 class Customer { public int Id { get; set; } ... } class CustomerAddress { public in ...

随机推荐

  1. Linux 之加密类型,CA,Openssl,Openssh

    TCP/IP:安全 A------->B 机密性:明文传输(ftp,http,smtp,telnet),被窃听 完整性:消息被篡改 身份验证:你访问的主机就是你真实要访问的那台,而不是钓鱼网站 ...

  2. Scala中的None,Nothing,Null,Nil

    在scala中这四个类型名称很类似,作用确实完全不同的. None是一个object,是Option的子类型,定义如下 case object None extends Option[Nothing] ...

  3. leetcode-javascript

    1. Largest Number For example, given [3, 30, 34, 5, 9], the largest formed number is 9534330. // wro ...

  4. Diamond使用向导

    一.背景描述                     Diamond是淘宝内部使用的一个管理持久配置的系统,它的特点是简单.可靠.易用,目前淘宝内部绝大多数系统的配置,由diamond来进行统一管理. ...

  5. Net分布式系统之四:RabbitMQ消息队列应用

    消息通信组件Net分布式系统的核心中间件之一,应用与系统高并发,各个组件之间解耦的依赖的场景.本框架采用消息队列中间件主要应用于两方面:一是解决部分高并发的业务处理:二是通过消息队列传输系统日志.目前 ...

  6. Arcgis Server发布服务

    提到Arcgis Server 服务的发布,做起来貌似很简单,就算电脑再卡,只要鼠标还能点,一个小时肯定能搞定,但是当你遇到问题的时候,就头大了,也许搞上个一两天都摸不着头脑,最后你采取的措施可能是一 ...

  7. 更新lispbox中的ccl和slime版本

    首先C-x C-f然后输入~,找到.emacs文件,根据slime官方文档说明的添加如下代码到文件末尾,重启一下emacs,slime就编译好了,然后这段代码就可以删除.否则每次启动emacs就算不用 ...

  8. unity3d 知识点随记

    1.transform.translate是增加transform面板相应的数值x,y,z是以本地坐标系为方向:transform.transformdirection是以世界坐标系为方向,可以去测试 ...

  9. Mysql Communication link failure :1153 Got a packet bigger than 'max_allowed_packet' bytes

    出现这种情况: 临时解决方法是: 登录mysql: 执行: set global max_allowed_packet=1000000000;       set global net_buffer_ ...

  10. Java线程的5个使用技巧

    萝卜白菜各有所爱.像小编我就喜欢Java.学无止境,这也是我喜欢它的一个原因.日常工作中你所用到的工具,通常都有些你从来没有了解过的东西,比方说某个方法或者是一些有趣的用法.比如说线程.没错,就是线程 ...