zoukankan      html  css  js  c++  java
  • Dapper and Repository Pattern in MVC

    大家好,首先原谅我标题是英文的,因为我想不出好的中文标题。

    这里我个人写了一个Dapper.net 的Repository模式的底层基础框架。

    涉及内容:

    Dapper.net结合Repository的设计,可切换不同数据库及当前操作数据库的事务支持,依赖注入(工具:Autofac)。

    项目可直接在此基础框架上开发。

    该底层架构分层参考:

    Nopcommerce:https://www.nopcommerce.com

     以及自己累积的经验分层及设计

    项目结构图:

    DapperRepository.Core: 放置相关数据接口和实体类

    DapperRepository.Data:数据操作层,实现具体Repository和数据库连接及访问

    DapperRepository.Services:业务逻辑层,处理相关业务逻辑

    DapperRepository.Web:web端,客户端操作

    以下简称Core、Data、Services、Web

    数据库脚本:

    创建数据库:

    复制代码
    USE [master]
    GO
    
    /****** Object:  Database [DapperRepositoryDb]    Script Date: 2/28/2019 2:59:41 PM ******/
    CREATE DATABASE [DapperRepositoryDb]
     CONTAINMENT = NONE
     ON  PRIMARY 
    ( NAME = N'DapperRepositoryDb', FILENAME = N'C:Program FilesMicrosoft SQL ServerMSSQL11.MSSQLSERVERMSSQLDATADapperRepositoryDb.mdf' , SIZE = 4096KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )
     LOG ON 
    ( NAME = N'DapperRepositoryDb_log', FILENAME = N'C:Program FilesMicrosoft SQL ServerMSSQL11.MSSQLSERVERMSSQLDATADapperRepositoryDb_log.ldf' , SIZE = 1024KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET COMPATIBILITY_LEVEL = 110
    GO
    
    IF (1 = FULLTEXTSERVICEPROPERTY('IsFullTextInstalled'))
    begin
    EXEC [DapperRepositoryDb].[dbo].[sp_fulltext_database] @action = 'enable'
    end
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ANSI_NULL_DEFAULT OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ANSI_NULLS OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ANSI_PADDING OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ANSI_WARNINGS OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ARITHABORT OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET AUTO_CLOSE OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET AUTO_CREATE_STATISTICS ON 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET AUTO_SHRINK OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET AUTO_UPDATE_STATISTICS ON 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET CURSOR_CLOSE_ON_COMMIT OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET CURSOR_DEFAULT  GLOBAL 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET CONCAT_NULL_YIELDS_NULL OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET NUMERIC_ROUNDABORT OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET QUOTED_IDENTIFIER OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET RECURSIVE_TRIGGERS OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET  DISABLE_BROKER 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET AUTO_UPDATE_STATISTICS_ASYNC OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET DATE_CORRELATION_OPTIMIZATION OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET TRUSTWORTHY OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET ALLOW_SNAPSHOT_ISOLATION OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET PARAMETERIZATION SIMPLE 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET READ_COMMITTED_SNAPSHOT OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET HONOR_BROKER_PRIORITY OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET RECOVERY SIMPLE 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET  MULTI_USER 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET PAGE_VERIFY CHECKSUM  
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET DB_CHAINING OFF 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET FILESTREAM( NON_TRANSACTED_ACCESS = OFF ) 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET TARGET_RECOVERY_TIME = 0 SECONDS 
    GO
    
    ALTER DATABASE [DapperRepositoryDb] SET  READ_WRITE 
    GO
    复制代码

    创建表和演示数据:

    复制代码
    USE [DapperRepositoryDb]
    GO
    
    /****** Object:  Table [dbo].[Customer]    Script Date: 2019/2/28 14:54:06 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [dbo].[Customer](
        [Id] [INT] IDENTITY(1,1) NOT NULL,
        [Username] [NVARCHAR](32) NOT NULL,
        [Email] [NVARCHAR](128) NOT NULL,
        [Active] [BIT] NOT NULL,
        [CreationTime] [DATETIME] NOT NULL,
     CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    /****** Object:  Table [dbo].[CustomerRole]    Script Date: 2019/2/28 14:54:26 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [dbo].[CustomerRole](
        [Id] [INT] IDENTITY(1,1) NOT NULL,
        [Name] [NVARCHAR](32) NOT NULL,
        [SystemName] [NVARCHAR](32) NOT NULL,
        [CreationTime] [DATETIME] NOT NULL,
     CONSTRAINT [PK_CustomerRole] PRIMARY KEY CLUSTERED 
    (
        [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY]
    
    GO
    
    /****** Object:  Table [dbo].[Customer_CustomerRole_Mapping]    Script Date: 2019/2/28 14:54:40 ******/
    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE TABLE [dbo].[Customer_CustomerRole_Mapping](
        [CustomerId] [INT] NOT NULL,
        [CustomerRoleId] [INT] NOT NULL
    ) ON [PRIMARY]
    
    GO
    
    ALTER TABLE [dbo].[Customer_CustomerRole_Mapping]  WITH CHECK ADD  CONSTRAINT [FK_Customer_CustomerRole_Mapping_Customer] FOREIGN KEY([CustomerId])
    REFERENCES [dbo].[Customer] ([Id])
    ON DELETE CASCADE
    GO
    
    ALTER TABLE [dbo].[Customer_CustomerRole_Mapping] CHECK CONSTRAINT [FK_Customer_CustomerRole_Mapping_Customer]
    GO
    
    ALTER TABLE [dbo].[Customer_CustomerRole_Mapping]  WITH CHECK ADD  CONSTRAINT [FK_Customer_CustomerRole_Mapping_CustomerRole] FOREIGN KEY([CustomerRoleId])
    REFERENCES [dbo].[CustomerRole] ([Id])
    ON DELETE CASCADE
    GO
    
    ALTER TABLE [dbo].[Customer_CustomerRole_Mapping] CHECK CONSTRAINT [FK_Customer_CustomerRole_Mapping_CustomerRole]
    GO
    
    
    INSERT INTO [dbo].[CustomerRole]
               ([Name]
               ,[SystemName]
               ,[CreationTime])
         VALUES
               ('Admin',
               'Admin',
               GETDATE())
    GO
    
    INSERT INTO [dbo].[CustomerRole]
               ([Name]
               ,[SystemName]
               ,[CreationTime])
         VALUES
               ('Guest',
               'Guest',
               GETDATE())
    GO
    复制代码

    接下俩详细分析:

    实体基类BaseEntity:

    复制代码
    namespace DapperRepository.Core
    {
        public abstract class BaseEntity
        {
            public int Id { get; set; }
        }
    }
    复制代码

    Core:

    建立一个名为Data的文件夹放置IDbSession和IRepository:

    IDbSession:

    复制代码
    using System;
    using System.Data;
    
    namespace DapperRepository.Core.Data
    {
        public interface IDbSession : IDisposable
        {
            IDbConnection Connection { get; }
            IDbTransaction Transaction { get; }
    
            IDbTransaction BeginTrans(IsolationLevel isolation = IsolationLevel.ReadCommitted);
            void Commit();
            void Rollback();
        }
    }
    复制代码

    这个接口定义数据数据连接对象属性和事务属性,以及相关事务性的操作方法。

    IRepository:

    复制代码
    using System.Data;
    using System.Collections.Generic;
    
    namespace DapperRepository.Core.Data
    {
        public interface IRepository<T> where T : BaseEntity
        {
            /// <summary>
            /// 根据主键获取一条数据
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据</returns>
            T GetById(string sql, object param = null, bool buffered = true, int? commandTimeout = null,
                CommandType? commandType = null, bool useTransaction = false);
    
            /// <summary>
            /// 根据相关条件获取一条数据
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据</returns>
            T GetBy(string sql, object param = null, bool buffered = true, int? commandTimeout = null,
                CommandType? commandType = null, bool useTransaction = false);
    
            /// <summary>
            /// 获取数据列表(所有、部分或者分页获取)
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据列表</returns>
            IEnumerable<T> GetList(string sql, object param = null, bool buffered = true, int? commandTimeout = null,
                CommandType? commandType = null, bool useTransaction = false);
    
            /// <summary>
            /// 添加数据
            /// </summary>
            /// <param name="entity">要添加的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(一般为添加的Id)</returns>
            dynamic Insert(T entity, int? commandTimeout = null, bool useTransaction = false);
    
            /// <summary>
            /// 修改数据
            /// </summary>
            /// <param name="entity">要修改的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(true or false)</returns>
            bool Update(T entity, int? commandTimeout = null, bool useTransaction = false);
    
            /// <summary>
            /// 删除数据
            /// </summary>
            /// <param name="entity">要删除的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(true or false)</returns>
            bool Delete(T entity, int? commandTimeout = null, bool useTransaction = false);
    
            /// <summary>
            /// 执行对象sql语句(一般需要事务处理)
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行受影响的行数</returns>
            int Execute(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null,
                bool useTransaction = true);
        }
    }
    复制代码

    这里定义相关数据操作(增删查改)的基础方法。或许有些开发者会问为何分页,执行存储过程的基础方法都没有。这里我个人说明下,因为dapper.net是精简orm,并不像EF那样集成了很多方法和扩展,dapper主要还是依赖于写的sql语句的处理逻辑。所以这里分页的话你写好sql语句或者存储过程并调用GetList方法即可。

    创建一个名为Domain的文件夹放置相关实体:

    DataBaseType枚举(数据库类型:MSSQL、MYSQL、ORACLE...)

    复制代码
    namespace DapperRepository.Core.Domain
    {
        public enum DatabaseType
        {
            Mssql,
            Mysql,
            Oracle
        }
    }
    复制代码

    相关实体:

    Customer:

    复制代码
    using System;
    
    namespace DapperRepository.Core.Domain.Customers
    {
        public class Customer : BaseEntity
        {
            public string Username { get; set; }
    
            public string Email { get; set; }
    
            public bool Active { get; set; }
    
            public DateTime CreationTime { get; set; }
        }
    }
    复制代码

    CustomerRole:

    复制代码
    namespace DapperRepository.Core.Domain.Customers
    {
        public class CustomerRole : BaseEntity
        {
            public string Name { get; set; }
    
            public string SystemName { get; set; }
        }
    }
    复制代码

    Dto实体CustomerDtoModel:

    复制代码
    using System;
    
    namespace DapperRepository.Core.Domain.Customers
    {
        public class CustomerDtoModel
        {
            public int Id { get; set; }
    
            public string Username { get; set; }
    
            public string Email { get; set; }
    
            public bool Active { get; set; }
    
            public DateTime CreationTime { get; set; }
    
            public virtual CustomerRole CustomerRole { get; set; }
        }
    }
    复制代码

    Data:

    新建一个类ConnConfig用于获取数据连接字符串:

    复制代码
    using System.Configuration;
    using System.Web.Configuration;
    
    namespace DapperRepository.Data
    {
        public class ConnConfig
        {
            private readonly static Configuration Config = WebConfigurationManager.OpenWebConfiguration("~");
    
            /// <summary>
            /// mssql 连接字符串
            /// </summary>
            private static string _mssqlConnectionString = Config.AppSettings.Settings["MssqlConnectionString"].Value;
            /// <summary>
            /// mysql 连接字符串
            /// </summary>
            private static string _mysqlConnectionString = Config.AppSettings.Settings["MysqlConnectionString"].Value;
            /// <summary>
            /// oracle 连接字符串
            /// </summary>
            private static string _oracleConnectionString = Config.AppSettings.Settings["OracleConnectionString"].Value;
    
            public static string MssqlConnectionString
            {
                get { return _mssqlConnectionString; }
                set { _mssqlConnectionString = value; }
            }
    
            public static string MysqlConnectionString
            {
                get { return _mysqlConnectionString; }
                set { _mysqlConnectionString = value; }
            }
    
            public static string OracleConnectionString
            {
                get { return _oracleConnectionString; }
                set { _oracleConnectionString = value; }
            }
        }
    }
    复制代码

    工厂类SessionFactory用于切换某个数据库以及创建数据库会话:

    复制代码
    using System.Data;
    using System.Data.OracleClient;
    using System.Data.SqlClient;
    using DapperRepository.Core.Data;
    using DapperRepository.Core.Domain;
    using MySql.Data.MySqlClient;
    
    namespace DapperRepository.Data
    {
        public class SessionFactory
        {
            private static IDbConnection CreateConnection(DatabaseType dataType)
            {
                IDbConnection conn;
                switch (dataType)
                {
                    case DatabaseType.Mssql:
                        conn = new SqlConnection(ConnConfig.MssqlConnectionString);
                        break;
                    case DatabaseType.Mysql:
                        conn = new MySqlConnection(ConnConfig.MysqlConnectionString);
                        break;
                    case DatabaseType.Oracle:
                        conn = new OracleConnection(ConnConfig.OracleConnectionString);
                        break;
                    default:
                        conn = new SqlConnection(ConnConfig.MssqlConnectionString);
                        break;
                }
    
                conn.Open();
    
                return conn;
            }
    
            /// <summary>
            /// 创建数据库连接会话
            /// </summary>
            /// <returns></returns>
            public static IDbSession CreateSession(DatabaseType databaseType)
            {
                IDbConnection conn = CreateConnection(databaseType);
                IDbSession session = new DbSession(conn);
                return session;
            }
        }
    }
    复制代码

    IDbSession的实现类DbSession:

    复制代码
    using System;
    using System.Data;
    using DapperRepository.Core.Data;
    
    namespace DapperRepository.Data
    {
        public class DbSession : IDbSession
        {
            private IDbConnection _connection;
            private IDbTransaction _transaction;
    
            public DbSession(IDbConnection conn)
            {
                _connection = conn;
            }
    
            public IDbConnection Connection
            {
                get { return _connection; }
            }
    
            public IDbTransaction Transaction
            {
                get { return _transaction; }
            }
    
            public IDbTransaction BeginTrans(IsolationLevel isolation = IsolationLevel.ReadCommitted)
            {
                _transaction = _connection.BeginTransaction(isolation);
    
                return _transaction;
            }
    
            public void Commit()
            {
                _transaction.Commit();
            }
    
            public void Rollback()
            {
                _transaction.Rollback();
            }
    
            public void Dispose()
            {
                if (_transaction != null)
                {
                    _transaction.Dispose();
                    _transaction = null;
                }
    
                if (_connection != null)
                {
                    if (_connection.State == ConnectionState.Open)
                        _connection.Close();
    
                    _connection.Dispose();
                    _connection = null;
                }
    
                GC.SuppressFinalize(this);
            }
        }
    }
    复制代码

    抽象类RepositoryBase用于实现IRepository接口的方法:

    复制代码
    using System;
    using System.Linq;
    using System.Data;
    using System.Collections.Generic;
    using Dapper;
    using DapperExtensions;
    using DapperRepository.Core;
    using DapperRepository.Core.Data;
    using DapperRepository.Core.Domain;
    
    namespace DapperRepository.Data
    {
        public abstract class RepositoryBase<T> where T : BaseEntity
        {
            protected virtual IDbSession DbSession
            {
                get { return SessionFactory.CreateSession(DataType); }
            }
    
            /// <summary>
            /// 数据库类型(MSSQL,MYSQL...)
            /// </summary>
            protected abstract DatabaseType DataType { get; }
    
            /// <summary>
            /// 根据主键获取一条数据
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据</returns>
            public virtual T GetById(string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, bool useTransaction = false)
            {
                if (string.IsNullOrEmpty(sql))
                    return null;
    
                IDbSession session = DbSession;
    
                T result = session.Connection.Query<T>(sql, param, null, buffered, commandTimeout, commandType).SingleOrDefault();
    
                session.Dispose(); // 释放资源
    
                return result;
            }
    
            /// <summary>
            /// 根据相关条件获取一条数据
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据</returns>
            public virtual T GetBy(string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, bool useTransaction = false)
            {
                if (string.IsNullOrEmpty(sql))
                    return null;
    
                IDbSession session = DbSession;
    
                T result = session.Connection.Query<T>(sql, param, null, buffered, commandTimeout, commandType).FirstOrDefault();
    
                session.Dispose(); // 释放资源
    
                return result;
            }
    
            /// <summary>
            /// 获取数据列表(所有、部分或者分页获取)
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="buffered">是否缓冲查询数据,详细信息:https://dapper-tutorial.net/buffered </param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>当前查询数据列表</returns>
            public virtual IEnumerable<T> GetList(string sql, object param = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null, bool useTransaction = false)
            {
                if (string.IsNullOrEmpty(sql))
                    return null;
    
                IEnumerable<T> results;
    
                IDbSession session = DbSession;
                if (useTransaction)
                {
                    session.BeginTrans();
    
                    results = session.Connection.Query<T>(sql, param, session.Transaction, buffered, commandTimeout, commandType).ToList();
                    session.Commit();
                }
                else
                {
                    results = session.Connection.Query<T>(sql, param, null, buffered, commandTimeout, commandType).ToList();
                }
    
                session.Dispose(); // 释放资源
    
                return results;
            }
    
            /// <summary>
            /// 添加数据
            /// </summary>
            /// <param name="entity">要添加的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(一般为添加的Id)</returns>
            public virtual dynamic Insert(T entity, int? commandTimeout = null, bool useTransaction = false)
            {
                IDbSession session = DbSession;
    
                try
                {
                    if (useTransaction)
                    {
                        session.BeginTrans();
    
                        dynamic result = session.Connection.Insert(entity, session.Transaction, commandTimeout);
                        session.Commit();
                        return result;
                    }
                    else
                    {
                        return session.Connection.Insert(entity, null, commandTimeout);
                    }
                }
                catch (Exception)
                {
                    if (useTransaction)
                    {
                        session.Rollback();
                    }
    
                    return null;
                }
                finally
                {
                    session.Dispose(); // 释放资源
                }
            }
    
            /// <summary>
            /// 修改数据
            /// </summary>
            /// <param name="entity">要修改的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(true or false)</returns>
            public virtual bool Update(T entity, int? commandTimeout = null, bool useTransaction = false)
            {
                IDbSession session = DbSession;
    
                try
                {
                    if (useTransaction)
                    {
                        session.BeginTrans();
    
                        bool result = session.Connection.Update(entity, session.Transaction, commandTimeout);
                        session.Commit();
                        return result;
                    }
                    else
                    {
                        return session.Connection.Update(entity, null, commandTimeout);
                    }
                }
                catch (Exception)
                {
                    if (useTransaction)
                    {
                        session.Rollback();
                    }
    
                    return false;
                }
                finally
                {
                    session.Dispose(); // 释放资源
                }
            }
    
            /// <summary>
            /// 删除数据
            /// </summary>
            /// <param name="entity">要删除的实体对象</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行结果(true or false)</returns>
            public virtual bool Delete(T entity, int? commandTimeout = null, bool useTransaction = false)
            {
                IDbSession session = DbSession;
    
                try
                {
                    if (useTransaction)
                    {
                        session.BeginTrans();
    
                        bool result = session.Connection.Delete(entity, session.Transaction, commandTimeout);
                        session.Commit();
                        return result;
                    }
                    else
                    {
                        return session.Connection.Delete(entity, null, commandTimeout);
                    }
                }
                catch (Exception)
                {
                    if (useTransaction)
                    {
                        session.Rollback();
                    }
    
                    return false;
                }
                finally
                {
                    session.Dispose(); // 释放资源
                }
            }
    
            /// <summary>
            /// 执行对象sql语句(一般需要事务处理)
            /// </summary>
            /// <param name="sql">sql语句或者存储过程</param>
            /// <param name="param">语句参数</param>
            /// <param name="commandTimeout">执行超时时间</param>
            /// <param name="commandType">命令类型(sql语句或是存储过程)</param>
            /// <param name="useTransaction">是否开启事务</param>
            /// <returns>执行受影响的行数</returns>
            public virtual int Execute(string sql, object param = null, int? commandTimeout = null, CommandType? commandType = null, bool useTransaction = true)
            {
                if (string.IsNullOrEmpty(sql))
                    return 0;
    
                IDbSession session = DbSession;
    
                try
                {
                    if (useTransaction)
                    {
                        session.BeginTrans();
    
                        int rowsAffected = session.Connection.Execute(sql, param, session.Transaction, commandTimeout, commandType);
                        session.Commit();
    
                        return rowsAffected;
                    }
                    else
                    {
                        return session.Connection.Execute(sql, param, null, commandTimeout, commandType);
                    }
                }
                catch (Exception)
                {
                    if (useTransaction)
                    {
                        session.Rollback();
                    }
    
                    return 0;
                }
                finally
                {
                    session.Dispose(); // 释放资源
                }
            }
        }
    }
    复制代码

     新建接口ICustomerRepository:

    复制代码
    using System.Collections.Generic;
    using DapperRepository.Core.Data;
    using DapperRepository.Core.Domain.Customers;
    
    namespace DapperRepository.Data.Repositories.Customers
    {
        public interface ICustomerRepository : IRepository<Customer>
        {
            #region Customer
    
            Customer GetCustomerById(int id);
            
            CustomerDtoModel GetCustomerBy(int id);
    
            IEnumerable<CustomerDtoModel> GetAllCustomers();
    
            int InsertCustomer(Customer customer, int roleId);
            int UpdateCustomer(Customer customer, int roleId);
    
            #endregion
    
            #region Customer Roles
    
            // IEnumerable<CustomerRole> GetCustomerRoles();
    
            #endregion
        }
    }
    复制代码

    对应实现类CustomerRepository:

    复制代码
    using System;
    using System.Text;
    using System.Data;
    using System.Collections.Generic;
    using System.Linq;
    using Dapper;
    using DapperRepository.Core.Data;
    using DapperRepository.Core.Domain;
    using DapperRepository.Core.Domain.Customers;
    
    namespace DapperRepository.Data.Repositories.Customers
    {
        public class CustomerRepository : RepositoryBase<Customer>, ICustomerRepository
        {
            protected override DatabaseType DataType
            {
                get { return DatabaseType.Mssql; }
            }
    
            public Customer GetCustomerById(int id)
            {
                if (id == 0)
                    return null;
    
                const string sql = "SELECT [Id],[Username],[Email],[Active],[CreationTime] FROM Customer WHERE Id=@id";
                return GetById(sql, new { id }, commandType: CommandType.Text);
            }
    
            public CustomerDtoModel GetCustomerBy(int id)
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("SELECT c.Id,c.Username,c.Email,c.Active,c.CreationTime,cr.Id,cr.Name,cr.SystemName FROM Customer c ");
                sb.Append("JOIN Customer_CustomerRole_Mapping crm ON c.Id = crm.CustomerId ");
                sb.Append("JOIN CustomerRole cr ON crm.CustomerRoleId = cr.Id WHERE c.Id = @id");
    
                string sql = sb.ToString();
                IDbSession session = DbSession;
    
                using (IDbConnection conn = session.Connection)
                {
                    var customers = conn.Query<CustomerDtoModel, CustomerRole, CustomerDtoModel>(sql, (c, cr) =>
                    {
                        c.CustomerRole = cr;
                        return c;
                    }, new { id }).FirstOrDefault();
    
                    return customers;
                }
            }
    
            public IEnumerable<CustomerDtoModel> GetAllCustomers()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("SELECT c.Id,c.Username,c.Email,c.Active,c.CreationTime,cr.Id,cr.Name,cr.SystemName FROM Customer c ");
                sb.Append("JOIN Customer_CustomerRole_Mapping crm ON c.Id = crm.CustomerId ");
                sb.Append("JOIN CustomerRole cr ON crm.CustomerRoleId = cr.Id");
    
                string sql = sb.ToString();
                IDbSession session = DbSession;
                try
                {
                    using (IDbConnection conn = session.Connection)
                    {
                        session.BeginTrans();
    
                        var customers = conn.Query<CustomerDtoModel, CustomerRole, CustomerDtoModel>(sql, (c, cr) =>
                        {
                            c.CustomerRole = cr;
                            return c;
                        }, transaction: session.Transaction);
                        session.Commit();
    
                        return customers;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
                finally
                {
                    session.Dispose();
                }
            }
    
            public int InsertCustomer(Customer customer, int roleId)
            {
                StringBuilder builder = new StringBuilder(50);
                builder.Append("DECLARE @insertid INT;");
                builder.Append("INSERT INTO dbo.Customer( Username,Email,Active,CreationTime ) VALUES ( @Username,@Email,@Active,@CreationTime );");
                builder.Append("SET @insertid = SCOPE_IDENTITY();");
                builder.Append("INSERT INTO [dbo].[Customer_CustomerRole_Mapping]( CustomerId,CustomerRoleId ) VALUES ( @insertid,@roleId );");
    
                return Execute(builder.ToString(), new
                {
                    customer.Username,
                    customer.Email,
                    customer.Active,
                    customer.CreationTime,
                    roleId
                }, commandType: CommandType.Text);
            }
    
            /// <summary>
            /// 更新信息(事实上用户有可能具有多个角色,我这里为了演示方便就假设用户只有一个角色处理了)
            /// </summary>
            /// <param name="customer"></param>
            /// <param name="roleId">对应角色id</param>
            /// <returns></returns>
            public int UpdateCustomer(Customer customer, int roleId)
            {
                StringBuilder builder = new StringBuilder(50);
                builder.Append("UPDATE [dbo].[Customer] SET [Username] = @Username,[Email] = @Email,[Active] = @Active WHERE [Id] = @Id;");
                builder.Append("UPDATE [dbo].[Customer_CustomerRole_Mapping] SET [CustomerRoleId] = @CustomerRoleId WHERE [CustomerId] = @CustomerId;");
    
                return Execute(builder.ToString(), new
                {
                    customer.Username,
                    customer.Email,
                    customer.Active,
                    customer.Id,
                    @CustomerRoleId = roleId,
                    @CustomerId = customer.Id
                }, commandType: CommandType.Text);
            }
    
            #region Customer Roles
            /*
            public IEnumerable<CustomerRole> GetCustomerRoles()
            {
                const string sql = "SELECT Id,Name,SystemName FROM CustomerRole";
    
                IDbSession session = DbSession;
    
                try
                {
                    using (IDbConnection conn = session.Connection)
                    {
                        session.BeginTrans();
    
                        IEnumerable<CustomerRole> result = conn.Query<CustomerRole>(sql, transaction: session.Transaction);
                        session.Commit();
    
                        return result;
                    }
                }
                catch (Exception)
                {
                    return null;
                }
                finally
                {
                    session.Dispose();
                }
            }
             */
            #endregion
        }
    }
    复制代码

    Services:

    接口ICustomerService:

    复制代码
    using System.Collections.Generic;
    using DapperRepository.Core.Domain.Customers;
    
    namespace DapperRepository.Services.Customers
    {
        public interface ICustomerService
        {
            #region Customer
    
            Customer GetCustomerById(int customerId);
    
            CustomerDtoModel GetCustomerBy(int id);
    
            IEnumerable<CustomerDtoModel> GetAllCustomers();
    
            int InsertCustomer(Customer customer, int roleId);
    
            int UpdateCustomer(Customer customer, int roleId);
    
            bool DeleteCustomer(Customer customer);
    
            #endregion
    
            #region CustomerRole
    
            //IEnumerable<CustomerRole> GetCustomerRoles();
    
            #endregion
        }
    }
    复制代码

    对应实现类CustomerService:

    复制代码
    using System;
    using System.Collections.Generic;
    using DapperRepository.Core.Domain.Customers;
    using DapperRepository.Data.Repositories.Customers;
    
    namespace DapperRepository.Services.Customers
    {
        public class CustomerService : ICustomerService
        {
            private readonly ICustomerRepository _repository;
    
            public CustomerService(ICustomerRepository repository)
            {
                _repository = repository;
            }
    
            #region Custoemr
    
            public Customer GetCustomerById(int customerId)
            {
                if (customerId == 0)
                    return null;
    
                return _repository.GetCustomerById(customerId);
            }
    
            public CustomerDtoModel GetCustomerBy(int id)
            {
                if (id <= 0)
                    return null;
    
                return _repository.GetCustomerBy(id);
            }
    
            public IEnumerable<CustomerDtoModel> GetAllCustomers()
            {
                return _repository.GetAllCustomers();
            }
    
            public int InsertCustomer(Customer customer, int roleId)
            {
                if (customer == null)
                    throw new ArgumentNullException("customer");
    
                return _repository.InsertCustomer(customer, roleId);
            }
    
            public int UpdateCustomer(Customer customer, int roleId)
            {
                if (customer == null)
                    throw new ArgumentNullException("customer");
    
                return _repository.UpdateCustomer(customer, roleId);
            }
    
            public bool DeleteCustomer(Customer customer)
            {
                return _repository.Delete(customer);
            }
    
            #endregion
    
            #region Customer Roles
            /*
            public IEnumerable<CustomerRole> GetCustomerRoles()
            {
                return _repository.GetCustomerRoles();
            }
            */
            #endregion
        }
    }
    复制代码

    Web:

    建立文件夹Infrastructure用于存放依赖注入的配置类Bootstrapper:

    复制代码
    using System.Reflection;
    using System.Web.Mvc;
    using Autofac;
    using Autofac.Integration.Mvc;
    using DapperRepository.Data.Repositories.Customers;
    using DapperRepository.Services.Customers;
    
    namespace DapperRepository.Web.Infrastructure
    {
        public class Bootstrapper
        {
            public static void Run()
            {
                SetAutofacContainer();
            }
    
            private static void SetAutofacContainer()
            {
                ContainerBuilder builder = new ContainerBuilder();
    
                builder.RegisterControllers(Assembly.GetExecutingAssembly());
    
                // Repositories
                builder.RegisterType<CustomerRepository>().As<ICustomerRepository>().InstancePerLifetimeScope();
                builder.RegisterType<CustomerRoleRepository>().As<ICustomerRoleRepository>().InstancePerLifetimeScope();
    
                // Services
                builder.RegisterType<CustomerService>().As<ICustomerService>().InstancePerLifetimeScope();
                builder.RegisterType<CustomerRoleService>().As<ICustomerRoleService>().InstancePerLifetimeScope();
    
                IContainer container = builder.Build();
    
                DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
            }
        }
    }
    复制代码

    添加控制器CustomerController:

    复制代码
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web.Mvc;
    using DapperRepository.Core.Domain.Customers;
    using DapperRepository.Services.Customers;
    using DapperRepository.Web.Models.Customers;
    
    namespace DapperRepository.Web.Controllers
    {
        public class CustomerController : Controller
        {
            private readonly ICustomerService _customerService;
            private readonly ICustomerRoleService _customerRoleService;
    
            public CustomerController(ICustomerService customerService, ICustomerRoleService customerRoleService)
            {
                _customerService = customerService;
                _customerRoleService = customerRoleService;
            }
    
            public ActionResult Index()
            {
                IEnumerable<CustomerDtoModel> customers = _customerService.GetAllCustomers();
                return View(customers);
            }
    
            public ActionResult Create()
            {
                var customerRoles = _customerRoleService.GetCustomerRoles().Select(x => new SelectListItem
                {
                    Text = x.Name,
                    Value = x.Id.ToString()
                }).ToList();
    
                CustomerModel model = new CustomerModel
                {
                    AvailableRoles = customerRoles
                };
    
                return View(model);
            }
    
            [HttpPost]
            public ActionResult Create(CustomerModel model)
            {
                if (ModelState.IsValid)
                {
                    Customer customer = new Customer
                    {
                        Username = model.Username,
                        Email = model.Email,
                        Active = model.Active,
                        CreationTime = DateTime.Now
                    };
    
                    _customerService.InsertCustomer(customer, model.RoleId);
                }
                return RedirectToAction("Index");
            }
    
            public ActionResult Edit(int id)
            {
                CustomerDtoModel customer = _customerService.GetCustomerBy(id);
                if (customer == null)
                    return RedirectToAction("Index");
    
                var customerRoles = _customerRoleService.GetCustomerRoles().Select(x => new SelectListItem
                {
                    Text = x.Name,
                    Value = x.Id.ToString(),
                    Selected = x.Id == customer.CustomerRole.Id
                }).ToList();
    
                CustomerModel model = new CustomerModel
                {
                    Id = customer.Id,
                    Username = customer.Username,
                    Email = customer.Email,
                    Active = customer.Active,
                    CreationTime = customer.CreationTime,
                    RoleId = customer.CustomerRole.Id,
                    AvailableRoles = customerRoles
                };
    
                return View(model);
            }
    
            [HttpPost]
            public ActionResult Edit(CustomerModel model)
            {
                Customer customer = _customerService.GetCustomerById(model.Id);
                if (customer == null)
                    return RedirectToAction("Index");
    
                if (ModelState.IsValid)
                {
                    customer.Username = model.Username;
                    customer.Email = model.Email;
                    customer.Active = model.Active;
    
                    _customerService.UpdateCustomer(customer, model.RoleId);
                }
                return RedirectToAction("Index");
            }
    
            [HttpPost]
            public ActionResult Delete(int id)
            {
                Customer customer = _customerService.GetCustomerById(id);
                if (customer == null)
                    return Json(new { status = false, msg = "No customer found with the specified id" });
    
                try
                {
                    bool result = _customerService.DeleteCustomer(customer);
                    return Json(new { status = result, msg = result ? "deleted successfully" : "deleted failed" });
                }
                catch (Exception ex)
                {
                    return Json(new { status = false, msg = ex.Message });
                }
            }
        }
    }
    复制代码

    Index.cshtml:

    复制代码
    @model IEnumerable<DapperRepository.Core.Domain.Customers.CustomerDtoModel>
    @{
        ViewBag.Title = "Index";
    }
    
    <h2>Data List</h2>
    <div class="content-header clearfix">
        <h5 class="pull-left">
            <a href="@Url.Action("Create")" class="btn btn-primary">Add</a>
        </h5>
    </div>
    <table class="table table-bordered">
        <tr>
            <th>Id</th>
            <th>Name</th>
            <th>Email</th>
            <th>Role</th>
            <th>Active</th>
            <th>CreationTime</th>
            <th>Action</th>
            @foreach (var item in Model)
            {
            <tr>
                <td>@item.Id</td>
                <td>@item.Username</td>
                <td>@item.Email</td>
                <td>@item.CustomerRole.Name</td>
                <td>@item.Active</td>
                <td>@item.CreationTime</td>
                <td>
                    <a class="btn btn-default" href="@Url.Action("Edit", new {id = item.Id})">Edit</a> 
                    <a class="btn btn-default del" href="javascript:void(0)" data-id="@item.Id">Delete</a>
                </td>
            </tr>
            }
        </table>
        <script>
            $(function () {
                $('a.del').click(function () {
                    if (confirm("Are you sure to delete the data?")) {
                        $.ajax({
                            url: "@Url.Action("Delete")",
                            type: "POST",
                            data: { id: $(this).data("id") }
                        }).done(function (data) {
                            if (data.status) {
                                location.reload();
                            } else {
                                console.log(data.msg);
                            }
                        }).error(function (xhr) {
                            console.log(xhr.message);
                        });
                    }
                });
            })
        </script>
    复制代码

    相关Create.cshtml及Edit.cshtml这里我就不给出了,大家可下载完整项目。

    GitHub地址:https://github.com/Olek-HZQ/DapperRepositoryDemo

    项目演示地址:http://dapperrepository.coolwecool.com

  • 相关阅读:
    Android studio测试软件——Monkey学习及运用
    MockPlus原型设计介绍
    MockPlus,一款好用的原型设计软件
    44道JavaScript难题 ---- 送命题
    使用JSONP实现跨域
    XML-RPC简单理解与博客园的MetaWeblog协议
    新型冠状病毒防控知识问答
    树莓派搭建个人服务器
    树莓派也跑Docker和.NET Core
    BugNet使用指南
  • 原文地址:https://www.cnblogs.com/zhangruisoldier/p/10451640.html
Copyright © 2011-2022 走看看