Imports System.Data.Common
Imports System.Data.SqlClient
Imports System.Data.SQLite
Imports MySql.Data.MySqlClient
Imports UTS_Core.Database.Mssql
Imports UTS_Core.Database.Mysql
Imports UTS_Core.Database.Sqlite


Namespace Database
    ''' <summary>
    ''' 数据库通用命令执行器
    ''' 时间：2020-12-21
    ''' 作者：ML
    ''' 版本：1.0
    ''' </summary>
    Public Class DbExecutor
        Implements IDisposable
        ''' <summary>
        ''' 数据库类型,目前支持Mysql与Sqlite
        ''' </summary>
        Enum DbTypeEnum
            Mysql
            Sqlite
            Mssql
        End Enum


        Private ReadOnly _connectionString As String '数据库连接语句

        Private ReadOnly _dbType As DbTypeEnum '数据库类型

        Private _connection As DbConnection '数据库连接句柄

        Private _command As DbCommand '数据库命令句柄

        Private _dataAdapter As DbDataAdapter '数据库查询填充器句柄

        Private _transaction As DbTransaction '数据库事务句柄

        Private _commandHelper As DbCmdHelper '数据库语句填充助手

        Sub New(type As DbTypeEnum, connectionString As String)
            _dbType = type
            _connectionString = connectionString
            InitByDbType(_dbType)
        End Sub

        Private Sub InitByDbType(type As DbTypeEnum)
            Select Case type
                Case DbTypeEnum.Mysql
                    _connection = New MySqlConnection()
                    _command = _connection.CreateCommand()
                    _dataAdapter = New MySqlDataAdapter() With {.MissingSchemaAction = MissingSchemaAction.AddWithKey}

                    _commandHelper = New MysqlCmdHelper()
                Case DbTypeEnum.Sqlite
                    _connection = New SQLiteConnection()
                    _command = _connection.CreateCommand()
                    _dataAdapter = New SQLiteDataAdapter() With {.MissingSchemaAction = MissingSchemaAction.AddWithKey}

                    _commandHelper = New SqliteCmdHelper()
                Case DbTypeEnum.Mssql
                    _connection = New SqlConnection()
                    _command = _connection.CreateCommand()
                    _dataAdapter = New SqlDataAdapter() With {.MissingSchemaAction = MissingSchemaAction.AddWithKey}

                    _commandHelper = New MssqlCmdHelper()
            End Select
        End Sub


        Public ReadOnly Property DatabaseType() As DbTypeEnum
            Get
                Return _dbType
            End Get
            'Set(value As DbTypeEnum)
            '    _dbType = value
            '    '执行上一个数据库的关闭操作
            '    InitByDbType(_dbType)
            'End Set
        End Property

        Public ReadOnly Property Connection() As DbConnection
            Get
                Return _connection
            End Get
        End Property


        Public ReadOnly Property Command() As DbCommand
            Get
                Return _command
            End Get
        End Property

        Public ReadOnly Property CmdHelper() As DbCmdHelper
            Get
                Return _commandHelper
            End Get
        End Property


        ''' <summary>
        ''' 打开数据库连接
        ''' </summary>
        ''' <returns></returns>
        Public Function Open() As Boolean
            If _connection Is Nothing Then Return False
            If String.IsNullOrWhiteSpace(_connectionString) Then Return False
            Try
                _connection.ConnectionString = _connectionString
                _connection.Open()
            Catch ex As Exception
                Throw
            End Try
            Return True
        End Function

        ''' <summary>
        ''' 打开数据库连接
        ''' </summary>
        ''' <returns></returns>
        Public Async Function OpenAsync() As Task(Of Boolean)
            If _connection Is Nothing Then Return False
            If String.IsNullOrWhiteSpace(_connectionString) Then Return False
            Try
                _connection.ConnectionString = _connectionString
                Await _connection.OpenAsync()
            Catch ex As Exception
                Throw
            End Try
            Return True
        End Function

        ''' <summary>
        ''' 关闭数据库连接
        ''' </summary>
        Public Sub Close()
            If _connection Is Nothing Then Return
            If _connection.State = ConnectionState.Closed Then Return
            _connection.Close()
        End Sub

        ''' <summary>
        ''' 创建当前连接的命令执行句柄
        ''' </summary>
        ''' <returns></returns>
        Public Function CreateCommand() As DbCommand
            Return _connection.CreateCommand()
        End Function



        ''' <summary>
        ''' 运行非查询语句,返回执行该语句受到影响的行数
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Function ExecuteNonQuery(commandText As String) As Integer
            Dim result As Integer
            Try
                _command.CommandText = commandText
                result = _command.ExecuteNonQuery()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 运行非查询语句,返回执行该语句受到影响的行数
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Async Function ExecuteNonQueryAsync(commandText As String) As Task(Of Integer)
            Dim result As Integer
            Try
                _command.CommandText = commandText
                result = Await _command.ExecuteNonQueryAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行非查询语句,返回执行该语句受到影响的行数
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Function ExecuteNonQuery(commandText As String, commandParams As DbParameterCollection) As Integer
            Dim result As Integer
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = _command.ExecuteNonQuery()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行非查询语句,返回执行该语句受到影响的行数
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Async Function ExecuteNonQueryAsync(commandText As String, commandParams As DbParameterCollection) As Task(Of Integer)
            Dim result As Integer
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = Await _command.ExecuteNonQueryAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function


        ''' <summary>
        ''' 执行数据库语句,返回数据库读取流的句柄
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Function ExecuteReader(commandText As String) As DbDataReader
            Dim result As DbDataReader
            Try
                _command.CommandText = commandText
                result = _command.ExecuteReader()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 执行数据库语句,返回数据库读取流的句柄
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Async Function ExecuteReaderAsync(commandText As String) As Task(Of DbDataReader)
            Dim result As DbDataReader
            Try
                _command.CommandText = commandText
                result = Await _command.ExecuteReaderAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行数据库语句,返回数据库读取流的句柄
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Function ExecuteReader(commandText As String, commandParams As DbParameterCollection) As DbDataReader
            Dim result As DbDataReader
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = _command.ExecuteReader()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行数据库语句,返回数据库读取流的句柄
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Async Function ExecuteReaderAsync(commandText As String, commandParams As DbParameterCollection) As Task(Of DbDataReader)
            Dim result As DbDataReader
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = Await _command.ExecuteReaderAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 执行数据库语句,返回查询结果的第一行第一列的内容
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Function ExecuteScalar(commandText As String) As Object
            Dim result As Object
            Try
                _command.CommandText = commandText
                result = _command.ExecuteScalar()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 执行数据库语句,返回查询结果的第一行第一列的内容
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Async Function ExecuteScalarAsync(commandText As String) As Task(Of Object)
            Dim result As Object
            Try
                _command.CommandText = commandText
                result = Await _command.ExecuteScalarAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行数据库语句,返回查询结果的第一行第一列的内容
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Function ExecuteScalar(commandText As String, commandParams As DbParameterCollection) As Object
            Dim result As Object
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = _command.ExecuteScalar()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 使用命令参数模式执行数据库语句,返回查询结果的第一行第一列的内容
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Async Function ExecuteScalarAsync(commandText As String, commandParams As DbParameterCollection) As Task(Of Object)
            Dim result As Object
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                result = Await _command.ExecuteScalarAsync()
            Catch ex As Exception
                Throw
            End Try
            Return result
        End Function

        ''' <summary>
        ''' 执行数据库语句,返回执行结果返回的数据表,常用于查询命令
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <returns></returns>
        Public Function ExecuteDataTable(commandText As String, Optional withKey As Boolean = True) As DataTable
            Dim dataTable As New DataTable
            Try
                _command.CommandText = commandText
                If withKey Then
                    _dataAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey
                Else
                    _dataAdapter.MissingSchemaAction = MissingSchemaAction.Add
                End If
                _dataAdapter.SelectCommand = _command
                _dataAdapter.Fill(dataTable)

            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
            Return dataTable
        End Function


        ''' <summary>
        ''' 执行数据库语句,返回执行结果返回的数据表,常用于查询命令
        ''' </summary>
        ''' <param name="commandText">执行的数据库命令文本</param>
        ''' <param name="commandParams">执行的数据库命令参数</param>
        ''' <returns></returns>
        Public Function ExecuteDataTable(commandText As String, commandParams As DbParameterCollection) As DataTable
            Dim dataTable As New DataTable
            Try
                _command.CommandText = commandText
                _command.Parameters.Clear()
                For Each param As DbParameter In commandParams
                    _command.Parameters.Add(param)
                Next
                _dataAdapter.SelectCommand = _command
                _dataAdapter.Fill(dataTable)
            Catch ex As Exception
                Throw
            End Try
            Return dataTable
        End Function

        ''' <summary>
        ''' 开启事务
        ''' </summary>
        ''' <returns></returns>
        Public Function BeginTransaction() As DbTransaction
            _transaction = _connection.BeginTransaction()
            Return _transaction
        End Function

        ''' <summary>
        ''' 提交事务
        ''' </summary>
        Public Sub CommitTransaction()
            Try
                _transaction.Commit()
            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' 回滚事务
        ''' </summary>
        Public Sub RollbackTransaction()
            Try
                _transaction.Rollback()
            Catch ex As Exception
                Throw
            End Try
        End Sub

        ''' <summary>
        ''' 创建数据参数
        ''' </summary>
        ''' <param name="type">参数数据类型</param>
        ''' <param name="ParameterName">参数名称</param>
        ''' <param name="value">参数值</param>
        ''' <returns></returns>
        Public Function CreateDbParameter(type As DbType, parameterName As String, value As Object) As DbParameter
            Dim dbParam As DbParameter = _command.CreateParameter()
            dbParam.DbType = type
            dbParam.ParameterName = parameterName
            dbParam.Value = value
            Return dbParam
        End Function

        ''' <summary>
        ''' 添加数据参数
        ''' </summary>
        ''' <param name="type"></param>
        ''' <param name="parameterName"></param>
        ''' <param name="value"></param>
        ''' <returns></returns>
        Public Function AddDbParameter(type As DbType, parameterName As String, value As Object) As DbParameter
            Dim dbParam As DbParameter = _command.CreateParameter()
            dbParam.DbType = type
            dbParam.ParameterName = parameterName
            dbParam.Value = value
            _command.Parameters.Add(dbParam)
            Return dbParam
        End Function

        ''' <summary>
        ''' 清空数据
        ''' </summary>
        Public Sub ClearDbParameter()
            _command.Parameters.Clear()
        End Sub


        ''' <summary>
        ''' 回收资源
        ''' </summary>
        Public Sub Dispose() Implements IDisposable.Dispose
            If _connection IsNot Nothing Then
                If _connection.State = ConnectionState.Open Then
                    _connection.Close()
                End If
                _connection.Dispose()
            End If

            If _command IsNot Nothing Then _command.Dispose()
            If _dataAdapter IsNot Nothing Then _dataAdapter.Dispose()

            GC.Collect() '对所有缓存垃圾进行回收
        End Sub
    End Class
End Namespace