1. Dapper

从字面理解,O是Object,对象;R是Relation,关系;M是Mapping,映射。

所以,用一句话概括就是:ORM是一种对象关系映射的技术。

  • Dapper是一款轻量级ORM工具。
  • Dapper是一个轻型的ORM类。代码就一个SqlMapper.cs文件,编译后就40K的一个很小的Dll.
  • Dapper很快,性能优越。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
  • 支持多数据库。。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server

https://github.com/StackExchange/Dapper

https://dapper-tutorial.net/dapper

1.1. 安装

推荐使用NuGet方式进行安装

安装后,项目中会自动添加Dapper的引用,

【packages.config】也会有对应的包配置

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Dapper" version="1.50.5" targetFramework="net46" />
</packages>

1.2. Dapper操作

以下所有操作均基于下面数据库连接配置的读取:

/// <summary>
/// 读取数据库连接配置
/// 需要添加引用 System.Configuration.dll
/// </summary>
static readonly string connStr = System.Configuration.ConfigurationManager.AppSettings["connStr"];

基于T_DOG表结构:

CREATE TABLE T_DOG
    (
      [ID] INT IDENTITY(1, 1) PRIMARY KEY ,
      [NAME] VARCHAR(32) ,
      [WEIGHT] FLOAT ,
      [BIRTH] DATE
    )

添加测试数据:

INSERT INTO dbo.T_DOG ( NAME, WEIGHT, BIRTH ) VALUES  ( '小黑',  3.1,  '2010-1-1')
INSERT INTO dbo.T_DOG ( NAME, WEIGHT, BIRTH ) VALUES  ( '小花',  2.5,  '2010-2-1')
INSERT INTO dbo.T_DOG ( NAME, WEIGHT, BIRTH ) VALUES  ( '小白',  2.2,  '2010-3-1')
INSERT INTO dbo.T_DOG ( NAME, WEIGHT, BIRTH ) VALUES  ( '二狗子',  4,  '2010-4-1')
INSERT INTO dbo.T_DOG ( NAME, WEIGHT, BIRTH ) VALUES  ( '斗牛',  5.7,  '2010-5-1')

Dog实体类:

public class Dog
{
    public int ID { get; set; }
    public string Name { get; set; }
    public double Weight { get; set; }
    public DateTime Birth { get; set; }
}

1.2.1. 强类型集合查询

Dapper 基于IDbConnection接口扩展了Query方法,所以在使用Dapper方法时需要添加Dapper程序集的using引用:

public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql
    , object param = null, SqlTransaction transaction = null, bool buffered = true)

执行查询,返回对应的泛型集合,Dapper会按照属性名称进行映射:

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG WHERE NAME LIKE @NAME ";
    object parameters = new { NAME = "%小%" };
    List<Dog> list = conn.Query<Dog>(sql, parameters).ToList();
}
using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG WHERE WEIGHT > @WEIGHT ";
    object parameters = new { WEIGHT = 2.5 };
    List<Dog> list = conn.Query<Dog>(sql, parameters).ToList();
}

1.2.2. 动态类型的查询

Query方法若为指定类型,即返回动态类型集合

public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql
    , object param = null, SqlTransaction transaction = null, bool buffered = true)
using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG WHERE WEIGHT > @WEIGHT ";
    object parameters = new { WEIGHT = 2.5 };
    List<dynamic> list = conn.Query(sql, parameters).ToList();
}

1.2.3. 增删改

这是一个简单的参数化insert,匿名类型对象,跟原始的SqlParameter相比要简单很多

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"INSERT INTO T_DOG(NAME,WEIGHT,BIRTH) VALUES(@NAME,@WEIGHT,@BIRTH) ";
    object parameters = new { NAME = "田园守护者", WEIGHT = 2.5, BIRTH = DateTime.Now };
    int res = conn.Execute(sql, parameters);
}

Bulk操作,批量化的操作,我们要做的就是将上面这个【对象】变成【对象集合】就可以了。

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"INSERT INTO T_DOG(NAME,WEIGHT,BIRTH) VALUES(@NAME,@WEIGHT,@BIRTH) ";
    List<Dog> parameters = new List<Dog>();
    parameters.Add(new Dog()
    { Name = "jack", Weight = 1.2, Birth = new DateTime(2012, 1, 1) });
    parameters.Add(new Dog()
    { Name = "lee", Weight = 1.1, Birth = new DateTime(2012, 1, 2) });
    parameters.Add(new Dog()
    { Name = "rock", Weight = 2.2, Birth = new DateTime(2012, 1, 3) });

    int res = conn.Execute(sql, parameters);
}

相应的删除、修改也是一样的套路。暂略...

1.2.4. 查询条件的IEnumerable支持

Dapper允许传入IEnumerable<int>类型,并自动进行转换查询

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG WHERE NAME IN @NAMES ";
    object parameters = new { NAMES = new string[] { "小黑", "小白", "小花" } };
    // 相当于执行 SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG WHERE NAME IN ('小黑', '小白', '小花')
    List<Dog> list = conn.Query<Dog>(sql, parameters).ToList();
}

1.2.5. 多映射

Dapper支持将一行结果值映射对应到多个对象,这样做可以大大提高效率。

在上述表T_DOG基础上再添加一张表T_PERSON,两表之间的关系为T_DOG.OWNER=T_PERSON.ID,SQL脚本如下:

-- 创建主人表
CREATE TABLE T_PERSON
    (
      ID INT IDENTITY(1, 1) PRIMARY KEY ,
      NAME VARCHAR(32)
    )
INSERT  INTO T_PERSON ( NAME ) VALUES  ( '二郎神' )
INSERT  INTO T_PERSON ( NAME ) VALUES  ( '孙悟空' )
-- 修改 表T_DOG结构,增加[OWNER]为狗主人
ALTER TABLE dbo.T_DOG ADD [OWNER] INT 

-- 根据体重设置新增的字段[OWNER]
UPDATE dbo.T_DOG SET OWNER = (CASE WHEN WEIGHT>2.5 THEN 1 ELSE 2 END);

对应的强类型如下:

public class Dog
{
    public int ID { get; set; }
    public string Name { get; set; }
    public double Weight { get; set; }
    public DateTime Birth { get; set; }
    /// <summary>
    /// 狗主人,也是一个对象
    /// </summary>
    public Person Owner { get; set; }
}

public class Person
{
    public int ID { get; set; }
    public string Name { get; set; }
}

传统方式都是在查询得到所有的Dog集合后,然后遍历再去查询所有Dog对象对应的Owner对象,当数据量很大时,此方式非常影响效率,而且很麻烦。

Query<TFirst, TSecond, TReturn>提供了映射到多个对象的方式,TFirst表示第一个对象,TSecond表示第二个对象,TReturn为返回对象。

Func<TFirst, TSecond, TReturn> map委托,参数为(TFirst, TSecond),需要返回TReturn类型对象,即在方法中需要指明如何关联。

public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(this IDbConnection cnn
, string sql, Func<TFirst, TSecond, TReturn> map
, object param = null
, ........);

关联的多个对象有重名时,按照顺序进行关联进行映射:

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"
SELECT A.ID,A.NAME,WEIGHT,BIRTH,PE.ID,PE.NAME FROM T_DOG A 
LEFT JOIN T_PERSON PE ON A.OWNER= PE.ID";
    List<Dog> list = conn.Query<Dog, Person, Dog>(sql
        , (dog, per) =>
            {
                dog.Owner = per;
                return dog;
            }).ToList();
}

1.2.6. 多映射-splitOn

当结果集映射到多个对象嵌套时,如下Company示例:

public class Company
{
    public int CID { get; set; }
    public string Name { get; set; }
    public Mailing Mailing { get; set; }
    public Physical Physical { get; set; }
}

public class Mailing
{
    public int MID { get; set; }
    public string Name { get; set; }
}

public class Physical
{
    public int PID { get; set; }
    public string Name { get; set; }
}

Company类和Mailing类、Physical类是关联关系。

上述案例中,对应的Mailing和Physical主键并不是默认的id,此处需要指定splitOn,如下:

using (IDbConnection conn = new SqlConnection(connStr))
{
    // 多映射到对象嵌套时,需要注意字段的顺序
    string sql = @"
SELECT 1 as cid,'iflytek' as name
,11 as mid,'[email protected]' as name
,22 as pid,'文津西路' as name
";
    Company result = conn.Query<Company, Mailing, Physical, Company>(sql
        , (com, mail, phy) =>
    {
        com.Mailing = mail;
        com.Physical = phy;
        return com;
    }, splitOn: "mid,pid").FirstOrDefault();
}

1.2.7. 多个结果集映射

Dapper支持在一次查询中将多个查询结果集映射到不同集合

using (IDbConnection conn = new SqlConnection(connStr))
{
    string sql = @"
SELECT ID,NAME,WEIGHT,BIRTH FROM T_DOG
SELECT ID,NAME FROM T_PERSON
SELECT 1 AS MID, '[email protected]' AS NAME 
";
    var multi = conn.QueryMultiple(sql);
    List<Dog> listDog = multi.Read<Dog>().ToList();
    List<Person> listPerson = multi.Read<Person>().ToList();
    Mailing mail = multi.Read<Mailing>().FirstOrDefault();
}

1.2.8. 存储过程的应用

基于前面章节所提到的存储过程sp_paged_data参见sp_paged_data

分页类Pager参见Pager

/// <summary>
/// Dapper 分页查询
/// </summary>
/// <typeparam name="T">需要映射到的实体类类型</typeparam>
/// <param name="sqlTable">关系表名</param>
/// <param name="sqlColumns">投影列,如*</param>
/// <param name="sqlWhere">条件子句(可为空),eg:and id=1</param>
/// <param name="sqlSort">排序语句(不可为空,必须有排序字段),eg:id</param>
/// <param name="pageIndex">当前页码索引号,从0开始</param>
/// <param name="pageSize">每页显示的记录条数</param>
/// <returns>分页对象</returns>
public static Pager<T> QueryByPager<T>(string sqlTable, string sqlColumns, string sqlWhere
, string sqlSort, int pageIndex, int pageSize)
{
    using (IDbConnection conn = new SqlConnection(connStr))
    {
        Pager<T> pager = new Pager<T>();
        var p = new DynamicParameters();
        p.Add("@sqlTable", sqlTable);
        p.Add("@sqlColumns", sqlColumns);
        p.Add("@sqlWhere", sqlWhere);
        p.Add("@sqlSort", sqlSort);
        p.Add("@pageIndex", pageIndex);
        p.Add("@pageSize", pageSize);
        // 指定记录总数为输出类型
        p.Add("@rowTotal", dbType: DbType.Int32, direction: ParameterDirection.Output);

        pager.Rows = conn.Query<T>("sp_paged_data", p, commandType: CommandType.StoredProcedure).ToList();
        pager.Total = p.Get<int>("@rowTotal");
        return pager;
    }
}

基于上面的QueryByPager方法封装,调用如下:

// 每页5条记录,查询第二页
Pager<Dog> res = DapperHelper.QueryByPager<Dog>("T_DOG", "ID,NAME,WEIGHT,BIRTH", "", "ID", 1, 5);

参考引用:

https://www.cnblogs.com/huangxincheng/p/5828470.html

https://blog.csdn.net/wyljz/article/details/68926745

https://stackoverflow.com/questions/25921402/how-do-i-get-multi-mapping-to-work-in-dapper

results matching ""

    No results matching ""