ServiceStack.OrmLite中的一些"陷阱"(1)
使用过ServiceStack.Ormlite的人都应该知道,其作为一个轻量级的ORM,使用的便捷度非常高,用起来就一个字:爽!
而支撑其便捷度的,是库内大量地使用了扩展方法及静态变量。
首先先从源头入手分析(以下以Sqlite为例):
OrmLiteConfig.DialectProvider = SqliteOrmLiteDialectProvider.Instance;
using (IDbConnection db = "~/db.sqlite".MapAbsolutePath().OpenDbConnection())
{
db.CreateTable<User>();
db.Insert(new User("Hello", "Password"));
}
其中MapAbsolutePath()是转换为绝对路径,这里不详细分析。而OPenDbConnection()则是OrmLiteConfig.cs上的扩展方法,其调用链如下:
public static IDbConnection OpenDbConnection(this string dbConnectionStringOrFilePath)
{
var sqlConn = dbConnectionStringOrFilePath.ToDbConnection(DialectProvider);
sqlConn.Open();
return sqlConn;
}
public static IDbConnection ToDbConnection(this string dbConnectionStringOrFilePath)
{
return dbConnectionStringOrFilePath.ToDbConnection(DialectProvider);
} public static IDbConnection ToDbConnection(this string dbConnectionStringOrFilePath, IOrmLiteDialectProvider dialectProvider)
{
var dbConn = dialectProvider.CreateConnection(dbConnectionStringOrFilePath, options: null);
return dbConn;
}
从重载方法中可以看出如果不提供IOrmLiteDialectProvider 参数的话是会使用OrmLiteConfig.DialectProvider (type:IOrmLiteDialectProvider)这个静态属性作为默认值的。而IOrmLiteDialectProvider 的作用就是ORM基于不同数据库语言的实现,ORM生成各自的SQL语句都靠它。
那么,既然有 ToDbConnection(string,IOrmLiteDialectProvider) 这样的函数,难道就可以在同一个项目中混合使用多个不同数据库语言的IDbConnect 了吗?(有可能项目有这样的要求)
例如这样:
var sqliteDb = "sqlitexxxx".ToDbConnection(SqliteOrmLiteDialectProvider.Instance);
var mysqlDb = "mysqlxxxx".ToDbConnection(MySqlDialectProvider.Instance);
我只能说:太!天!真!了!在OrmLite中大量地使用了OrmLiteConfig.DialectProvider 静态属性,以WriteConnectionExtensions.Delete<T>为例:
public static int Delete<T>(this IDbConnection dbConn, Expression<Func<T, bool>> where)
{
return dbConn.Exec(dbCmd => dbCmd.Delete(where));
} public static int Delete<T>(this IDbCommand dbCmd, Expression<Func<T, bool>> where)
{
var ev = OrmLiteConfig.DialectProvider.SqlExpression<T>();
ev.Where(where);
return dbCmd.Delete(ev);
} public static T Exec<T>(this IDbConnection dbConn, Func<IDbCommand, T> filter)
{
var holdProvider = OrmLiteConfig.TSDialectProvider;
try
{
var ormLiteDbConn = dbConn as OrmLiteConnection;
if (ormLiteDbConn != null)
OrmLiteConfig.TSDialectProvider = ormLiteDbConn.Factory.DialectProvider; using (var dbCmd = dbConn.CreateCommand())
{
dbCmd.Transaction = (ormLiteDbConn != null) ? ormLiteDbConn.Transaction : OrmLiteConfig.TSTransaction;
dbCmd.CommandTimeout = OrmLiteConfig.CommandTimeout;
var ret = filter(dbCmd);
LastCommandText = dbCmd.CommandText;
return ret;
}
}
finally
{
OrmLiteConfig.TSDialectProvider = holdProvider;
}
}
上述代码中可以看出,IDbCommand的Delete扩展方法中就使用了OrmLiteConfig.DialectProvider 静态属性,所以我们使用前必须赋予初始值。
有细心的网友可能会发现,在Exec方法中用到的Provider是TSDialectProvider 而非 DialectProvider,过中原由得慢慢分析。
[ThreadStatic]
public static IOrmLiteDialectProvider TSDialectProvider; private static IOrmLiteDialectProvider dialectProvider;
public static IOrmLiteDialectProvider DialectProvider
{
get
{
if (dialectProvider == null)
{
throw new ArgumentNullException("DialectProvider",
"You must set the singleton 'OrmLiteConfig.DialectProvider' to use the OrmLiteWriteExtensions");
}
return TSDialectProvider ?? dialectProvider;
}
set
{
dialectProvider = value;
}
}
先看TSDialectProvider,这是线程安全的静态变量。反而比较有意思的是DialectProvider,首先在get的时候dialectProvider 字段不能为null,否则会抛出异常。但是返回时却优先返回TSDialectProvider,而不是dialectProvider。为什么呢?
我觉得这是出于便捷性和多线程方面的考虑。
首先是便捷性,如果不便捷而较为常规的做法是怎样,我的实现是直接提供TSDialectProvider。
[ThreadStatic]
private static IOrmLiteDialectProvider tsDialectProvider; public static IOrmLiteDialectProvider DialectProvider
{
get
{
return tsDialectProvider;
}
set
{
tsDialectProvider = value;
}
}
多线程使用时必先在打开连接前先初始化DialectProvider。
public class OrmLiteTest
{
public static void Main(string[] args)
{
new Thread(SqliteTest).Start("sqlite");
new Thread(MySqlTest).Start("mysql");
} static void SqliteTest(string path)
{
OrmLiteConfig.DialectProvider = SqliteOrmLiteDialectProvider.Instance;
var db = ((string)path).OpenDbConnection();
//TODO sth.
}
static void MySqlTest(string path)
{
OrmLiteConfig.DialectProvider = MySqlDialectProvider.Instance;
var db = ((string)path).OpenDbConnection();
//TODO sth.
}
}
这里顺道把多线程也解决了,通常只使用一种数据库语言的时候,需要并发执行数据库操作(多个线程,多个IDbConnection)时,每次都需提前设置OrmLiteConfig.DialectProvider 反而会显得烦琐。
return TSDialectProvider ?? dialectProvider;
因为一般情况下TSDialectProvider默认为null,除非需要用到多种数据库才需要手动设置。可以说,TSDialectProvider就是专门为多数据库语言而设的。
ServiceStack.OrmLite中的一些"陷阱"(1)的更多相关文章
- ServiceStack.OrmLite中的一些"陷阱"(2)
注:此系列不是说ServiceStack.OrmLite的多个陷阱,这仅仅个人认为是某一个陷阱(毕竟我踩坑了)而引发的思考. 前文说到了项目需要使用两种不同的数据库语言,虽说前文问题已基本解决了,但是 ...
- ServiceStack.OrmLite中的一些"陷阱"(3)
前文说到如果使用多数据库(不同SQL方言)时要如何开发?其实前文(第二篇)也有“透露”到.就是直接使用库提供的OrmLiteConnection 及OrmLiteConnectionFactory(I ...
- ServiceStack.OrmLite 调用存储过程
最近在做关于ServiceStack.OrmLite调用存储过程时,有问题.发现ServiceStack.OrmLite不能调用存储过程,或者说不能实现我想要的需求.在做分页查询时,我需要传入参数传出 ...
- ServiceStack.OrmLite
ServiceStack.OrmLite 谈谈我的入门级实体框架Loogn.OrmLite 每次看到有新的ORM的时候,我总会留意一下,因为自己也写过一个这样的框架,人总是有比较之心的.我可能会d ...
- ServiceStack.OrmLite T4模板使用记录
前言 最近研究了下ServiceStack.OrmLite,文档中也提到了使用T4模板对数据库中已经有了表进行实体的映射,这里也顺便记录下使用的步骤和情况. 开始使用 引用T4模板 首先我们创建一个工 ...
- ServiceStack.OrmLite 入门(一)
软件环境: Win7 x64 SP1 SQL Server 2008r2 Visual Studio 2017 Professional 目标:取出示例数据库 ReportServer 的表 Role ...
- JavaScript中的this陷阱的最全收集 没有之一
当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概 念,可能真解释不清楚.有句话这么说:如果你不能向一个6岁小孩解 ...
- 转:JavaScript中的this陷阱的最全收集
在其他地方看到的,觉得解释的狠详细,特此分享 当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程.事件驱动.面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清 ...
- ServiceStack.OrmLite 学习笔记7-复杂点的使用1
复杂点的使用1 先看看这2个类 class Customer { public int Id { get; set; } ... } class CustomerAddress { public in ...
随机推荐
- 自己写的 限制文本框TEdit中只能输入数字
procedure TForm4.Edit1KeyPress(Sender: TObject; var Key: Char); begin , #]) then begin Key := #; end ...
- HTTP权威协议笔记-4.连接管理
4.1 TCP连接 TCP为HTTP提供了一条可靠的比特传输管道,按顺序正确的传输,步骤如下: 浏览器解析主机名. 查询这个主机名的IP地址(DNS) 获得端口号. 浏览器对服务器该端口号发起连接. ...
- 7.openssl enc
对称加密工具.了解对称加密的原理后就很简单了. [root@xuexi tmp]# man enc NAME enc - symmetric cipher routines SYNOPSIS open ...
- 聊聊python 2中的编码
为什么需要编码: 计算机可以存储和处理二进制,那么从文字到计算机可以识别的二进制之间需要对应的关系,于是便有了ASCII,ASSCII使用7位字符,由于1byte=8bit,所以最高位补一个0,使用8 ...
- touches, targetTouches, changedTouches 区别
1. touches: A list of information for every finger currently touching the screen2. targetTouches: Li ...
- web测试常用的用例及知识
1. Web测试中关于登录的测试... 1 2. 搜索功能测试用例设计... 2 3. 翻页功能测试用例... 3 4. 输入框的测试... 5 5. ...
- ng-style 的坑 - 对性能的影响
本文地址:http://www.cnblogs.com/jying/p/5633203.html 熟悉 angular 的前端对ng-style 一定不陌生,这个家伙可以绑定一个函数,使得我们可以在函 ...
- leetCode 354. Russian Doll Envelopes
You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envel ...
- hdu4607 Park Visit(树的直径)
Park Visit Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total ...
- calc常用
Mod:求模(整数相除求余数), And:按位与 Or:按位或 Xor:按位异或 Lsh:按位左移 Not:按位取反 Int:取整数部分