.netorm连接mysql_在.NET数据库访问方面的Dapper类库介绍

在开发带数据库的.NET系统中我使用过各种方式,包括直接使用ADO.NET、使用基于ADO.NET封装的各类工具(其中有自己封装的)、还有各类ORM类库,比如NHibernate、MyBatisNet、Linq to SQL、Entity Framwrok等,在上面的工具或类库中,MyBatisNet一段时间曾是我的最爱:由于它基于XML的配置可以灵活适应一些特殊的场景,不过有时候在面对中小型项目时又觉得MyBatisNet有些大材小用,此外还有一个原因是MyBatisNet这个基于Java的MyBatis改造而来的项目最近几乎没有更新了。

很早就听说过Dapper这个类库了,只不过一直没有尝试使用,但是很早就知道它是国外大型IT问答社区StackOverFlow最早开发并开源的。最近用了一下,感觉确实很方便。Dapper的源代码放在github上托管,并且可以用NuGet方式添加到项目中,只不过我现在开发的桌面软件有一部分用户还在使用WindowsXP系统,因此不能使用高于.NET Framrwork4.5以上版本开发且开发工具是Visual Studio 2015,这也限制了我不能使用最新版本的Dapper,于是我选择了Dapper 1.50.2这个版本。

我们可以在Visual Studio 2015中直接使用NuGet来添加,具体办法就是“工具”-“NuGet包管理器”-“管理解决方案的BuGet程序包”,如下图所示:

67c573f5a92580dd9abdbc8d2780ff07.png

然后在弹出的窗口中搜索“Dapper”,如下图所示:

ab1aba18627ee9df46595b616b8e6f3d.png

在上述界面中可以选择安装到当前解决方案的那些项目中,并且还可以指定Dapper的版本。

本文的描述都是针对Dapper 1.50.2版本。

扩展方法介绍

在介绍Dapper之前首先要介绍一下.NE中的扩展方法。扩展方法是.NET3.5添加的一个特性,使用扩展方法可以让你为现有的类扩展方法而无需创建新的派生类。下面以一个例子来说明:

在我解析某个XML文件节点时,需要读取某个节点的属性,但是这个节点并不是一直有这个属性值,如下:

为了避免name属性不存在时抛出异常,我必须先进行判断,如下:

string name=string.Empty;

if (subNetworkNode.Attributes["name"] != null)

{

name=subNetworkNode.Attributes["name"].Value;

}

如果一个XML节点里有几个可能不存在的属性时,就需要处处这样判断了,于是我对代码进行了改进,针对此类情况定义了扩展方法,方法如下:

public static class ExtendMethodClass

{

///

/// 获取指定属性的值,如果没有设置指定属性名,则返回空字符串

///

/// XML节点的属性集合

/// 属性名

///

public static string GetAttributeValue(this XmlAttributeCollection attributes,string attributeName)

{

if (string.IsNullOrEmpty(attributeName))

{

throw new ArgumentNullException("attributeName", "不能为空");

}

if (attributes == null||attributes[attributeName]==null)

{

return string.Empty;

}

return attributes[attributeName].Value;

}

}

这样一来,原来的代码就可以写成如下了:

string name = subNetworkNode.Attributes.GetAttributeValue("name");

初一看,就像是XmlAttributeCollection这类原来就有GetAttributeValue(string attributeName)这样一个方法,其实这个方式是我们自己扩展的。

定义扩展方法有几点:

1、定义扩展方法的类必须用static修饰,即必须为静态类。

2、定义的扩展方法必须用static修饰,即必须为静态方法,同时方法的第一个参数前必须加this修饰,this后必须是类名,表示为this后的类添加扩展方法,如本例中this XmlAttributeCollection attributes表示为XmlAttributeCollection这个类添加扩展方法,如果需要在方法体内访问XmlAttributeCollection这个类的实例,通过后面的attributes参数即可(注意这个参数的名称可以随便取)。

Dapper介绍

通过上面的介绍,大家可以初步了解扩展方法是怎么回事。其实Dapper主要也是用了扩展方法为IDbConnection和IDataReader添加扩展方法,比如在SqlMapper.cs中有如下代码为IDbConnection添加扩展方法(节选):

//

/// Execute parameterized SQL.

///

/// The connection to query on.

/// The SQL to execute for this query.

/// The parameters to use for this query.

/// The transaction to use for this query.

/// Number of seconds before command execution timeout.

/// Is it a stored proc or a batch?

/// The number of rows affected.

public static int Execute(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, int? commandTimeout = null, CommandType? commandType = null)

{

var command = new CommandDefinition(sql, param, transaction, commandTimeout, commandType, CommandFlags.Buffered);

return ExecuteImpl(cnn, ref command);

}

///

/// Execute parameterized SQL.

///

/// The connection to execute on.

/// The command to execute on this connection.

/// The number of rows affected.

public static int Execute(this IDbConnection cnn, CommandDefinition command) => ExecuteImpl(cnn, ref command);

在SqlMapper.IDataReader.cs为IDataReader添加扩展方法的代码(节选):

///

/// Parses a data reader to a sequence of data of the supplied type. Used for deserializing a reader without a connection, etc.

///

/// The type to parse from the .

/// The data reader to parse results from.

public static IEnumerable Parse(this IDataReader reader)

{

if (reader.Read())

{

var deser = GetDeserializer(typeof(T), reader, 0, -1, false);

do

{

yield return (T)deser(reader);

} while (reader.Read());

}

}

///

/// Parses a data reader to a sequence of data of the supplied type (as object). Used for deserializing a reader without a connection, etc.

///

/// The data reader to parse results from.

/// The type to parse from the .

public static IEnumerable Parse(this IDataReader reader, Type type)

{

if (reader.Read())

{

var deser = GetDeserializer(type, reader, 0, -1, false);

do

{

yield return deser(reader);

} while (reader.Read());

}

}

在本人2011年7月25日写的一篇名为《利用ADO.NET的体系架构打造通用的数据库访问通用类》的博客当中介绍了ADO.NET的体系架构,如下图:

b9b8a301bef1fe2f5a049d183193a3f9.png

就是首先定义了一系列的借口,如IDbConnection之类的,任何基于数据库访问只要实现了接口的定义,就都能在.NET访问,包括了微软自己对SQL Server和Access等数据库的实现以及MySQL和Oracle针对这个定义的第三方实现(其实JDBC也是这个道理,只不过是基于Java实现罢了)。因为包括SQL Server/MySQL/Oracle/PostgreSQL/SQLite在内的数据库都实现了IDbConnection的定义,而Dapper又是基于IDbConnection的扩展,因此使用Dapper理论上可以访问任何支持ADO.NET访问的数据库(前提是需要相关的数据库驱动,dll形式)。

在使用Dapper的实际开发中,用得较多的还是针对IDbConnection的扩展方法,主要有:

int Execute():相当于Command.ExecuteNonQuery(),指定增加、删除、修改SQL语句,返回受影响的行数。

object ExecuteScalar():相当于Command. ExecuteScalar(),返回结果集第一行第一列,用于聚合函数等。

T ExecuteScalar():相当于Command. ExecuteScalar(),返回结果集第一行第一列,不过返回的结果指定了具体类型。

IDataReader ExecuteReader():相当于Command. ExecuteReader()。

IEnumerable Query()

IEnumerable Query()

IEnumerable Query()

IEnumerable Query()

dynamic QueryFirst()

dynamic QueryFirstOrDefault()

dynamic QuerySingle()

dynamic QuerySingleOrDefault()

IEnumerable Query()

T QueryFirst()

T QueryFirstOrDefault()

T QuerySingle()

T QuerySingleOrDefault()

IEnumerable Query()

object QueryFirst()

object QueryFirstOrDefault()

object QuerySingle()

object QuerySingleOrDefault()

对于上面各种类型的Query和返回结果,就是分几种情况:返回一个实现IEnumerable接口的结果集,返回单个结果,返回单个结果或在没有找到匹配结果下返回默认值(引用类型、数值类型、枚举、日期等的默认值)

基本用法

使用了Dapper之后,在插入或者查询时默认是按照数据库字段名与类属性名不区分大小写的情况下对应。

加入有在SQL Server中有如下表:

CREATE TABLE IF NOT EXISTS tblBay (

Id integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,

Name nvarchar(50) not null,

Desc nvarchar(100) not null

)

同时有如下类定义:

public class Bay

{

public int ID { get; set; }

public string Name { get; set; }

public string Desc { get; set; }

}

那么插入可以这么写:

string connectionString = ".";//将这里改成你自己的数据库连接字符串

string sqlInsert = "INSERT INTO tblBay(Name,Desc)VALUES(@Name,@Desc)";

SqlConnection connection = new SqlConnection(connectionString);

Bay bay = new Bay { Name = "test", Desc = "desc" };

connection.Execute(sqlInsert, bay);

查询可以这么写:

string connectionString = ".";//将这里改成你自己的数据库连接字符串

string sqlQuery = "select * from tblBay where Id=@Id";

int id = 1;

SqlConnection connection = new SqlConnection(connectionString);

IEnumerable bayList = connection. QueryFirstOrDefault(sqlQuery,new { @Id = id });

字段与属性不一致情况下关联

但是在某些情况下,比如使用MySQL数据库时我们可能会在由多个单词构成的字段名之间以下划线分割,如”user_id”、”user_name”等,而定义实体类时我们又将实体类的属性定义为UserId、UserName,那么就需要为他们之间建立关联,比较简单的一种方式就是在select的时候使用as。

假定在MySQL中存在如下表:

CREATE TABLE IF NOT EXISTS tblperson (

user_id integer NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE,

user_name nvarchar(50) not null,

email nvarchar(100) not null

)

而对应的实体类为:

public class Person

{

public int UserId { get; set; }

public string UserName { get; set; }

public string Email { get; set; }

}

那么插入可以这么写:

string connectionString = ".";//将这里改成你自己的数据库连接字符串

string sqlInsert = "INSERT INTO tblperson(user_name,email)VALUES(@Name,@Email)";

SqlConnection connection = new SqlConnection(connectionString);

Person person = new Person { UserName = "test", Email = "email@email.com" };

DynamicParameters parameters = = new DynamicParameters();

parameters.Add("@Name", person.UserName);

parameters.Add("@Email", person.Email);

connection.Execute(sqlInsert, parameters);

查询可以这么写:

string connectionString = ".";//将这里改成你自己的数据库连接字符串

string sqlQuery = "select user_id as userId,user_name as username,email from tblperson where user_id=@UserId";

int userId = 1;

SqlConnection connection = new SqlConnection(connectionString);

DynamicParameters parameters = = new DynamicParameters();

parameters.Add("@UserId ", userId);

IEnumerable bayList = connection. QueryFirstOrDefault(sqlQuery, parameters);

也就是数据库字段名与实体类属性名如果忽略大小写的情况下是一致的,则我们无需单独处理它们之间的映射关系,如果数据库字段名与实体类属性在忽略大小写的情况下仍然不一致,那么我们需要手动处理映射:在INSERT、DELETE、UPDATE时可以通过DynamicParameters来处理;在SELECT时可以通过在SQL语句中使用AS来处理。

有关Dapper的更进一步用法可以查看Dapper的用户手册或直接查看源代码。

周金桥

2018/04/22

相关资源:Dapper类库
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页