Dapper.Contrib 开发.net core程序,兼容多种数据库

Dapper.Contrib 开发.net core程序,兼容多种数据库

https://www.cnblogs.com/wuhuacong/p/9952900.html

使用Dapper.Contrib 开发.net core程序,兼容多种数据库
关于Dapper的介绍,我想很多人都对它有一定的了解,这个类似一个轻型的ORM框架是目前应用非常火的一个东西,据说各方面的性能都不错,而且可以支持多种数据库,在开始介绍这个文章之前,我花了不少功夫来学习了Dapper 的相关使用。Dapper.Contrib是对Dapper的进一步封装,使对象的基本增删改查等操作进一步简化,我做了一个案例使用Dapper.Contrib 开发.net core程序,测试它对多种数据库的处理。

1、Dapper.Contrib的使用
前面介绍过,Dapper.Contrib是对Dapper的进一步封装,使对象的基本增删改查等操作进一步简化。

它主要是通过特性映射的方式实现自定义类和数据库之间的关系处理,如下是实体类的定义信息。

复制代码
[Table("T_Customer")]
public class CustomerInfo
{
[ExplicitKey]//非自增长的用此标识
public virtual string ID { get; set; }

    public virtual string Name { get; set; }

    public virtual int Age { get; set; }

    public virtual string Creator { get; set; }

    public virtual DateTime CreateTime { get; set; }

}

复制代码
Dapper.Contrib的所有实体配置选项

Table:指定实体对应地数据库表名,如果类名和数据库表名不同,需要设置(如案例所示)
Key:指定此列为自动增长主键
ExplicitKey:指定此列为非自动增长主键(例如guid,字符串列)
Computed:计算属性,此列不作为更新
Write:指定列是否可写
通过定义好实体类和数据库表的映射关系,就可以通过强类型处理相关的接口了,如下所示。

复制代码
T Get(id);
IEnumerable GetAll();
int Insert(T obj);
int Insert(Enumerable list);
bool Update(T obj);
bool Update(Enumerable list);
bool Delete(T obj);
bool Delete(Enumerable list);
bool DeleteAll();
复制代码
这样通过映射指定表名或者字段信息后,就可以知道类和表之间的关系,可以封装对应的强类型处理接口了。

2、Dapper.Contrib 开发.net core程序
我们创建一个空白的.net core程序框架后,就在它的基础上做一些Dapper的数据库测试。

首先为了考虑多数据库的处理,我们需要创建一个配置文件,并可以动态配置不同的数据库,配置文件appSettings.json如下所示。

上面我配置了多种数据库的连接字符串,并且通过动态指定节点名称和数据库类型,来实现对项目指向不同数据库的访问。

例如我们准备需要让Dapper支持我们常见的数据库类型,如下定义数据库类型。

复制代码
///

/// 数据库类型定义
///

public enum DatabaseType
{
SqlServer, //SQLServer数据库
MySql, //Mysql数据库
Npgsql, //PostgreSQL数据库
Oracle, //Oracle数据库
Sqlite, //SQLite数据库
DB2 //IBM DB2数据库
}
复制代码
对于不同的数据库信息,我们需要根据不同的配置连接字符串,并创建对应的数据库连接对象供Dapper使用,如对于SQLServer的数据库,那么创建的是SqlConnection对象,对于Mysql,创建的是MySqlConnection连接对象,对于PostgreSQL对应的是NpgsqlConnection,以此类推。而Dapper则通过对连接对象的扩展实现了多种数据请求。

对于多数据库的支持,我们需要统一解析配置内容appSetting.json的内容,并返回不同数据库的连接对象,如下是连接工厂的统一处理方式,通过 CreateConnection() 返回配置的连接对象。

复制代码
///

/// 数据库连接辅助类
///

public class ConnectionFactory
{
///

/// 转换数据库类型
///

/// 数据库类型
///
private static DatabaseType GetDataBaseType(string databaseType)
{
DatabaseType returnValue = DatabaseType.SqlServer;
foreach (DatabaseType dbType in Enum.GetValues(typeof(DatabaseType)))
{
if (dbType.ToString().Equals(databaseType, StringComparison.OrdinalIgnoreCase))
{
returnValue = dbType;
break;
}
}
return returnValue;
}

    /// <summary>
    /// 获取数据库连接
    /// </summary>
    /// <returns></returns>
    public static IDbConnection CreateConnection()
    {
        IDbConnection connection = null;

        //获取配置进行转换
        var type = AppConfig.GetConfig("ComponentDbType");
        var dbType = GetDataBaseType(type);

        //DefaultDatabase 根据这个配置项获取对应连接字符串
        var database = AppConfig.GetConfig("DefaultDatabase");
        if (string.IsNullOrEmpty(database))
        {
            database = "sqlserver";//默认配置
        }
        var strConn = AppConfig.Configuration.GetConnectionString(database);

        switch (dbType)
        {
            case DatabaseType.SqlServer:
                connection = new System.Data.SqlClient.SqlConnection(strConn);
                break;
            case DatabaseType.MySql:
                connection = new MySql.Data.MySqlClient.MySqlConnection(strConn);
                break;
            case DatabaseType.Npgsql:
                connection = new Npgsql.NpgsqlConnection(strConn);
                break;
            case DatabaseType.Sqlite:
                connection = new SQLiteConnection(strConn);
                break;
            case DatabaseType.Oracle:
                connection = new Oracle.ManagedDataAccess.Client.OracleConnection(strConn);
                //connection = new System.Data.OracleClient.OracleConnection(strConn);
                break;
            case DatabaseType.DB2:
                //connection = new System.Data.OleDb.OleDbConnection(strConn);
                break;
        }

        return connection;
    }
}

复制代码
有了数据库对象工厂,我们的配置就可以动态化了。

下面我们来看看,获得这些连接对象后,如何通过Dapper.Contrib来获取对应的对象了,下面的类是常规的对数据库信息的处理,包括常规的增删改查等基础接口。

复制代码
///

/// 常规的数据访问层
///

public class Customer
{
public IDbConnection Connection
{
get
{
var connection = ConnectionFactory.CreateConnection();
connection.Open();
return connection;
}
}

    public IEnumerable<CustomerInfo> GetAll()
    {
        using (IDbConnection dbConnection = Connection)
        {
            return dbConnection.GetAll<CustomerInfo>();
            //return dbConnection.Query<CustomerInfo>("SELECT * FROM T_Customer");
        }
    }

    public CustomerInfo FindByID(string id)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return dbConnection.Get<CustomerInfo>(id);
            //string query = "SELECT * FROM T_Customer WHERE ID = @Id";
            //return dbConnection.Query<CustomerInfo>(query, new { Id = id }).FirstOrDefault();
        }
    }

    public bool Insert(CustomerInfo info)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Insert(info) > 0;
            result = true;
            //string query = "INSERT INTO T_Customer (ID, Name, Age, Creator, CreateTime)"
            //                + " VALUES(@ID, @Name, @Age, @Creator, @CreateTime)";
            //result = dbConnection.Execute(query, info) > 0;
        }
        return result;
    }

    public bool Update(CustomerInfo prod)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Update(prod);
            //string query = "UPDATE T_Customer SET Name = @Name,"
            //               + " Age = @Age, Creator= @Creator, [email protected]"
            //               + " WHERE ID = @ID";
            //result = dbConnection.Execute(query, prod) > 0;
        }
        return result;
    }
    public bool Delete(string id)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Delete(new CustomerInfo { ID = id });
            //string query = "DELETE FROM T_Customer WHERE ID = @Id";
            //result = dbConnection.Execute(query, new { ID = id }) > 0;
        }
        return result;
    }
    public bool DeleteAll()
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.DeleteAll<CustomerInfo>();
            //string query = "DELETE FROM T_Customer WHERE ID = @Id";
            //result = dbConnection.Execute(query, new { ID = id }) > 0;
        }
        return result;
    }
}

复制代码
其中的备注部分的代码是等同于上面的执行代码的,是Dapper 的SQL版本的一种处理方式。

我们看到,对于Customer表来说,使用对象的接口处理,我们已经隔离了很多硬编码的SQL处理,不过我们还可以对它进行进一步的优化处理。

我们定义一个通用的BaseDAL来剥离常规的增删改查处理,并且把同步和异步的操作分来两个文件来管理,同步处理的基类如下代码所示。

复制代码
///

/// 数据库访问基类
///

/// 实体类类型
public partial class BaseDAL where T : class
{
///

/// 对象的表名
///

public string TableName { get; set; }

    /// <summary>
    /// 主键属性对象
    /// </summary>
    public PropertyInfo PrimaryKey { get; set; }

    public BaseDAL()
    {
        this.TableName = EntityHelper.GetTableName(typeof(T));
        this.PrimaryKey = EntityHelper.GetSingleKey<T>();
    }

    /// <summary>
    /// 数据库连接
    /// </summary>
    protected IDbConnection Connection
    {
        get
        {
            var connection = ConnectionFactory.CreateConnection();
            connection.Open();
            return connection;
        }
    }

    /// <summary>
    /// 返回数据库所有的对象集合
    /// </summary>
    /// <returns></returns>
    public IEnumerable<T> GetAll()
    {
        using (IDbConnection dbConnection = Connection)
        {
            return dbConnection.GetAll<T>();
        }
    }

    /// <summary>
    /// 查询数据库,返回指定ID的对象
    /// </summary>
    /// <param name="id">主键的值</param>
    /// <returns></returns>
    public T FindByID(object id)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return dbConnection.Get<T>(id);
        }
    }

    /// <summary>
    /// 插入指定对象到数据库中
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public bool Insert(T info)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            dbConnection.Insert(info);
            result = true;
        }
        return result;
    }
    /// <summary>
    /// 插入指定对象集合到数据库中
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public bool Insert(IEnumerable<T> list)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Insert(list) > 0;
        }
        return result;
    }

    /// <summary>
    /// 更新对象属性到数据库中
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public bool Update(T info)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Update(info);
        }
        return result;
    }
    /// <summary>
    /// 更新指定对象集合到数据库中
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public bool Update(IEnumerable<T> list)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Update(list);
        }
        return result;
    }
    /// <summary>
    /// 从数据库中删除指定对象
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public bool Delete(T info)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Delete(info);
        }
        return result;
    }
    /// <summary>
    /// 从数据库中删除指定对象集合
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public bool Delete(IEnumerable<T> list)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.Delete(list);
        }
        return result;
    }
    /// <summary>
    /// 根据指定对象的ID,从数据库中删除指定对象
    /// </summary>
    /// <param name="id">对象的ID</param>
    /// <returns></returns>
    public bool Delete(object id)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            string query = string.Format("DELETE FROM {0} WHERE {1} = @id", TableName, PrimaryKey.Name);
            var parameters = new DynamicParameters();
            parameters.Add("@id", id);

            result = dbConnection.Execute(query, parameters) > 0;
        }
        return result;
    }
    /// <summary>
    /// 从数据库中删除所有对象
    /// </summary>
    /// <returns></returns>
    public bool DeleteAll()
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            result = dbConnection.DeleteAll<T>();
        }
        return result;
    }

}

复制代码
异步类的代码如下所示。

复制代码
///

/// 数据库访问基类
///

/// 实体类类型
public partial class BaseDAL where T : class
{
///

/// 返回数据库所有的对象集合
///

///
public virtual async Task<IEnumerable> GetAllAsync()
{
using (IDbConnection dbConnection = Connection)
{
return await dbConnection.GetAllAsync();
}
}

    /// <summary>
    /// 查询数据库,返回指定ID的对象
    /// </summary>
    /// <param name="id">主键的值</param>
    /// <returns></returns>
    public virtual async Task<T> FindByIDAsync(object id)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.GetAsync<T>(id);
        }
    }
    /// <summary>
    /// 插入指定对象到数据库中
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public virtual async Task<bool> InsertAsync(T info)
    {
        bool result = false;
        using (IDbConnection dbConnection = Connection)
        {
            await dbConnection.InsertAsync(info);
            result = true;
        }
        return await Task<bool>.FromResult(result);
    }

    /// <summary>
    /// 插入指定对象集合到数据库中
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public virtual async Task<bool> InsertAsync(IEnumerable<T> list)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.InsertAsync(list) > 0;
        }
    }
    /// <summary>
    /// 更新对象属性到数据库中
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public virtual async Task<bool> UpdateAsync(T info)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.UpdateAsync(info);
        }
    }

    /// <summary>
    /// 更新指定对象集合到数据库中
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public virtual async Task<bool> UpdateAsync(IEnumerable<T> list)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.UpdateAsync(list);
        }
    }

    /// <summary>
    /// 从数据库中删除指定对象
    /// </summary>
    /// <param name="info">指定的对象</param>
    /// <returns></returns>
    public virtual async Task<bool> DeleteAsync(T info)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.DeleteAsync(info);
        }
    }

    /// <summary>
    /// 从数据库中删除指定对象集合
    /// </summary>
    /// <param name="list">指定的对象集合</param>
    /// <returns></returns>
    public virtual async Task<bool> DeleteAsync(IEnumerable<T> list)
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.DeleteAsync(list);
        }
    }

    /// <summary>
    /// 根据指定对象的ID,从数据库中删除指定对象
    /// </summary>
    /// <param name="id">对象的ID</param>
    /// <returns></returns>
    public virtual async Task<bool> DeleteAsync(object id)
    {
        using (IDbConnection dbConnection = Connection)
        {
            string query = string.Format("DELETE FROM {0} WHERE {1} = @id", TableName, PrimaryKey.Name);
            var parameters = new DynamicParameters();
            parameters.Add("@id", id);

            return await dbConnection.ExecuteAsync(query, parameters) > 0;
        }
    }

    /// <summary>
    /// 从数据库中删除所有对象
    /// </summary>
    /// <returns></returns>
    public virtual async Task<bool> DeleteAllAsync()
    {
        using (IDbConnection dbConnection = Connection)
        {
            return await dbConnection.DeleteAllAsync<T>();
        }
    }
}

复制代码
这样,我们如果需要增加一个如客户信息表的管理类,就很简单的继承基类就可以了,代码很少,但是增删改查接口一个也少不了。

复制代码
///

/// 继承基类对象管理
///

public class CustomerDAL :BaseDAL
{
}
复制代码
为了测试一下数据访问层的处理接口,我创建了一个.net core的控制台程序进行测试,如下项目视图所示。

主要目的是确认数据处理的效果。

我们在Program.cs类里面增加相关的测试代码,为了简便和处理效果没有用UnitTest处理。

复制代码
//创建管理对象,并测试接口
var customer = new CustomerDAL();
var list = customer.GetAll();
foreach (var item in list)
{
Console.WriteLine(item.ToJson());
var info = customer.FindByID(item.ID);
Console.WriteLine(info.ToJson());
Console.WriteLine();
}

        //插入记录
        var insertInfo = new CustomerInfo() { Name = "test", Age = 30, Creator = "test" };
        var insertList = new List<CustomerInfo>() { insertInfo };
        var flag = customer.Insert(insertList);
        Console.WriteLine("插入操作" + (flag ? "成功" : "失败"));

        Console.WriteLine("插入的新内容");
        insertInfo = customer.FindByID(insertInfo.ID);
        Console.WriteLine(insertInfo.ToJson());

        Console.WriteLine("更新内容");
        insertInfo.Name = "Test" + DateTime.Now.ToShortDateString();
        flag = customer.Update(insertInfo);
        Console.WriteLine("更新操作" + (flag ? "成功" : "失败"));

        Console.WriteLine("更新的新内容");
        insertInfo = customer.FindByID(insertInfo.ID);
        Console.WriteLine(insertInfo.ToJson());

        Console.WriteLine("删除内容");
        flag = customer.Delete(insertInfo.ID);
        Console.WriteLine("删除操作" + (flag ? "成功" : "失败"));

        Console.WriteLine("所有内容");
        list = customer.GetAll();
        foreach (var item in list)
        {
            Console.WriteLine(item.ToJson());
            Console.WriteLine();
        }

        Console.ReadLine();

复制代码

测试Mysql、SQLite数据库同样没有问题

Mysql配置信息如下

处理的Mysql记录信息如下。

SQLite配置信息如下

处理SQLite数据信息如下

而在处理PostgreSQL的信息(配置节点npgsql里面)的时候,查询的主键好像和大小写有关系,导致插入记录出错。

而Oracle我采用的是Oracle.ManagedDataAccess.Core进行访问,由于我本地Oracle数据库侦听处理有点问题,因此没有测试成功,暂不予置评。

而对于数据库的支持问题,导致我重新审核一下是否采用Dapper.Contrib还是其他Dapper方式来构建数据库访问基类的问题,我需要兼容多种数据库的信息,并且能够尽可能的封装常规的增删改查等操作,其中目前的基类还没有加入更加复杂的查询操作,分页操作等功能,在解决这些困惑问题,才会继续考虑把底层支持的接口全部完善。

原文地址:https://www.cnblogs.com/Leo_wl/p/9959881.html

时间: 2024-10-03 01:44:31

Dapper.Contrib 开发.net core程序,兼容多种数据库的相关文章

最好用的兼容多种数据库通用高效的大数据分页功能

通用权限管理系统底层有一个通用分页查询功能,该功能可实现多种数据库的查询,支持多表关联分页查询,目前是最完善的分页功能实现. 下面代码是使用的方法截图: /////////////////////////////// 后台代码截图1 /////////////////////////////// 后台代码截图2 /////////////////////////////// 后台代码截图3 /////////////////////////////// 后台代码截图4 /////////////

Winform开发框架中实现同时兼容多种数据库类型处理

在很多应用系统里面,虽然一般采用一种数据库运行,但是由于各种情况的需要,可能业务系统会部署在不同类型的数据库上,如果开发的系统能够很方便支持多种数据库的切换,那可以为我们减少很多烦恼,同时提高系统的适应性和强壮型.还有一种情况,由于业务数据库的不断膨胀或者方便数据库的切割隔离,有时候也会把不同的业务数据库进行分拆,如权限提供数据库,客户关系管理数据库,工作流程数据库,企业营运数据库等等,因此在一个系统里面,同时使用2个或者以上的数据库的情况也是有的. 在我较早期的一篇随笔<Winform开发框架

ibatis 实现 物理级别的 分页 兼容多种数据库(转载)

最近在看iBatis时,想做用动态Sql做个分布.因为在做项目时用iBator工具生成没有分页的功能,只有一些我们常用的功能.所以要对生成后的代码做修改.我在Java高手真经的一书中看到有做了MySql SqlServer Oracle的分页.实现如下: MySql--> 首先说说MySql的分页语句 Sql代码 select  *  from   user   where ... order   by ... limit 10,25 [sql] view plaincopy 根据以上的语句我们

针对程序员的数据库原则

特别说明: 1.  本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2.  本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也可以参考,但许多观点不适合于KV数据库或内存数据库或者是基于SSD技术的数据库: 3.  本文未深入数据库优化中最核心的执行计划分析技术. 读者对像: 开发人员:如果你是做数据库开发,那本文的内容非常适合,因为本文是从程序员的角度来谈数据库性能优化. 架构师:如果你已经是数据库应用的架构师,那本文的

[转]面向程序员的数据库访问性能优化法则

原文地址:http://blog.csdn.net/yzsind/article/details/6059209 特别说明: 1.  本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2.  本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也可以参考,但许多观点不适合于KV数据库或内存数据库或者是基于SSD技术的数据库: 3.  本文未深入数据库优化中最核心的执行计划分析技术. 读者对像: 开发人员:如果你是做数据库开发,那

Oracle学习总结(8)—— 面向程序员的数据库访问性能优化法则

特别说明: 1.  本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2.  本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也可以参考,但许多观点不适合于KV数据库或内存数据库或者是基于SSD技术的数据库: 3.  本文未深入数据库优化中最核心的执行计划分析技术. 读者对像: 开发人员:如果你是做数据库开发,那本文的内容非常适合,因为本文是从程序员的角度来谈数据库性能优化. 架构师:如果你已经是数据库应用的架构师,那本文的

面向程序员的数据库访问性能优化法则

此文于2010-12-08被推荐到CSDN首页 如何被推荐? 面向程序员的数据库访问性能优化法则 特别说明: 1.  本文只是面对数据库应用开发的程序员,不适合专业DBA,DBA在数据库性能优化方面需要了解更多的知识: 2.  本文许多示例及概念是基于Oracle数据库描述,对于其它关系型数据库也可以参考,但许多观点不适合于KV数据库或内存数据库或者是基于SSD技术的数据库: 3.  本文未深入数据库优化中最核心的执行计划分析技术. 读者对像: 开发人员:如果你是做数据库开发,那本文的内容非常适

部署到Linux使用VS Code 开发.NET Core 应用程序

使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台 使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台. 前面讲解了VSCode开发调试 .NET Core.都只是在windows下运行. .NET Core真正的核心是跨平台,我们现在来了解学习 .NET Core 跨平台. 在windows 下开发.NET Core 应用程序,然后部署到Linux 平台运行. .NET Core RC2版基本上已经完成. https://github.c

使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台

使用VS Code 开发.NET Core 应用程序 部署到Linux 跨平台. 前面讲解了VSCode开发调试 .NET Core.都只是在windows下运行. .NET Core真正的核心是跨平台,我们现在来了解学习 .NET Core 跨平台. 在windows 下开发.NET Core 应用程序,然后部署到Linux 平台运行. .NET Core RC2版基本上已经完成. https://github.com/dotnet/cli/milestones 可以看到 1.0.0-rc2