C# 連接 Oracle數據庫增刪改查,事務


一. 前情提要

一般.NET環境連接Oracle數據庫,是通過 TNS/SQL.NET 配置文件,而 TNS 必須要 Oracle 客戶端(如果連接的是服務器的數據庫,本地還要裝一個 client ,還要把 TNS 文件放進去安裝路徑里面)

1. Using System.Data.OracleClient

微軟自帶的,據說已經不維護了,總之是需要客戶端的。

2. Oracle.DataAccess.dll

一般在 Oracle 安裝目錄下 product\11.2.0\dbhome_1\ODP.NET\bin\2.x 里面。但是我碰到的問題就是:

Oracle.DataAccess.Client.OracleException: The provider is not compatible with the version of Oracle client

無論是換 2.112.1 的Oracle.DataAccess.x86還是 4.112.3 的Oracle.DataAccess.x86.4,怎么都找不到原因。
沒錯,Oracle.DataAccess.dll是分32為和64位的,主要看你的客戶端版本

3. Oracle.ManagedDataAccess.dll(極力推薦)

Oracle官網為C#提供的全新ODP.NET方式的全托管驅動,並且還支持EF,支持分布式事務。
NuGet搜索一下就能找到,ASP.NET Core 版的也是有。
這三個 dll 使用的方式我覺得是沒有什么不同的(至少我還沒接觸到不同的地方)
但是這個 dll 的使用方法有些不同,后續講到

二. 操作類

1. 獲取連接字符串

  • 這里有個比較坑的地方。使用ConfigurationManager類的時候,讀取的web.config/App.config都必須要在“調用”項目中存在,而不是在“被調用”中。
    通俗點:我新建了了一個Common的項目,用來存放一些公共的工具類(比如連接數據庫、防注入、字符轉換等),里面寫一個OracleHelper類用來讀取數據庫。
    現在WebUI這個項目要調用到Common.OracleHelper里的方法,那么連接用的web.config/App.config就必須寫在WebUI項目下,而不是Common
// 1. 從 web.config 獲取(必須是非靜態類,不然會報錯)
private string connString = ConfigurationManager.ConnectionStrings["Conn_DB"].ToString();
// 但是后面的操作要想直接使用,而不用 new 一個對象的話,就需要在這里建一個用於初始化的字段。
private static OracleHelper _instance;

public static OracleHelper Instance
{
    get
    {
        if (_instance == null)
            _instance = new OracleHelper();
        return _instance;
    }
}


// 2. 直接寫,不需要配置文件
static string connString = "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=118.31.20.98)(PORT=33602))(CONNECT_DATA=(SERVICE_NAME=STUTEST)));Persist Security Info=True;User ID=WMSTEST;Password=WMSTEST;";

// 還有就是 ASP.NET Core 的注入構造函數,這個在文章最后

2. 查詢表數據

DataSet

/// <summary>
/// 查詢表數據(單表)
/// </summary>
/// <param name="sql">sql語句</param>
/// <returns></returns>
public static DataSet SelectData(string sql)
{
    DataSet ds = new DataSet();
    try
    {
        using (OracleConnection conn = new OracleConnection(Instance.connString))
        {
            OracleCommand cmd = new OracleCommand(sql, conn);
            OracleDataAdapter adapter = new OracleDataAdapter(cmd);
            adapter.Fill(ds);
            return ds;
        }
    }
    catch (Exception e)
    {
        Console.Write(e);
    }
    return null;
}

DataTable

/// <summary>
/// 查詢表數據(單表)
/// </summary>
/// <param name="sql">sql語句</param>
/// <returns></returns>
public static DataTable SelectData(string sql)
{
    DataTable dt = new DataTable();
    try
    {
        using (OracleConnection conn = new OracleConnection(Instance.connString))
        {
            OracleCommand cmd = new OracleCommand(sql, conn);
            OracleDataAdapter adapter = new OracleDataAdapter(cmd);
            adapter.Fill(dt);
            return dt;
        }
    }
    catch (Exception e)
    {
        Console.Write(e);
    }
    return null;
}

DataView

/// <summary>
/// 查詢表數據(單表)
/// </summary>
/// <param name="sql">sql語句</param>
/// <returns></returns>
public static DataView SelectData(string sql)
{
    DataTable dt = new DataTable();
    try
    {
        using (OracleConnection conn = new OracleConnection(Instance.connString))
        {
            OracleCommand cmd = new OracleCommand(sql, conn);
            OracleDataAdapter adapter = new OracleDataAdapter(cmd);
            adapter.Fill(dt);
            return dt.DefaultView;
        }
    }
    catch (Exception e)
    {
        Console.Write(e);
    }
    return null;
}

3. 增/刪/改

插入,刪除,修改都可用一個方法,執行語句相同,返回true則表示有數據收到影響

/// <summary>
/// 執行sql 語句
/// </summary>
/// <param name="sql"></param>
/// <returns>返回影響的行數</returns>
public static Boolean AddUpDelData(string sql)
{
    try
    {
        using (OracleConnection conn = new OracleConnection(Instance.connString))
        {
            conn.Open();
            OracleCommand cmd = new OracleCommand(sql, conn);
            int row = cmd.ExecuteNonQuery();
            conn.Close();
            if (row > 0)
            {
                return true;
            }
        }
    }
    catch (Exception e)
    {
        Console.Write(e);
    }
    return false;
}

4. 批量 增/刪/改(事務)

事務,事務是多條SQL語句一起執行,如果一條錯誤,那么將會回滾。這個在表之間主外鍵關系是有必要同時生效。只要把SQL語句放在List集合中,傳到方法中即可

/// <summary>
/// 執行sql List語句
/// </summary>
/// <param name="sqlText">需要執行的List</param>
/// <returns>返回true/false</returns>
public static Boolean ExeTransaction(List<string> sqlText)
{
    using (OracleConnection conn = new OracleConnection(Instance.connString))
    {
        conn.Open();
        OracleTransaction tran = conn.BeginTransaction();
        try
        {
                                
            OracleCommand cmd = new OracleCommand();
            cmd.Transaction = tran;
            cmd.Connection = conn;
            foreach(string item in sqlText)
            {
                cmd.CommandText = item;
                cmd.ExecuteNonQuery();
            }
            tran.Commit();
            return true;
        }
        catch (Exception et)
        {
            tran.Rollback();
            return false;
        }
        finally
        {
            conn.Close();
        }
    }
}

三. 配置項(這里我使用的是 Oracle.ManagedDataAccess.dll)

1. ASP.NET MVC

web.config

<connectionStrings>
    <add name="Conn_DB" connectionString="Data Source=(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = 
         (PROTOCOL = TCP)(HOST = 192.168.1.13)(PORT=8686)))(CONNECT_DATA =(SERVER = DEDICATED)
         (SERVICE_NAME = STUTEST)));User Id=WMSTEST;Password=WMSTEST;" providerName="Oracle.DataAccess.Client" />
  </connectionStrings>

下面分幾種情況:

1) 無配置文件,直接連接DB

無SQL*Net 配置文件tnsnames.ora

string conString = "User Id=hr; password=hr;Data Source=localhost:1521/orcl; Pooling=false;";

2) 使用配置文件方式

使用tnsnames.ora文件,此放置在應用程序同目錄,至於代碼中怎么引用 同目錄下的 TNS 我也沒嘗試過。tnsnames.ora內容:

ORCL =
    (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
    (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = orcl)
    )
    )

使用web.config/App.config配置文件定義別名(無tnsnames.ora文件)

<oracle.manageddataaccess.client>
  <version number="*">
    <dataSources>
       <dataSource alias="orcl" descriptor="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME = orcl)))"/>
     </dataSources>
   </version>
 </oracle.manageddataaccess.client>

使用TNS_ADMIN目錄:

<oracle.manageddataaccess.client>
  <version number="*">
    <settings>
           <setting name="TNS_ADMIN" value="C:\app\oracle\product\12.1.0\client_1\Network\Admin\"/>  
     </settings>
   </version>
 </oracle.manageddataaccess.client>

2. ASP.NET Core,我這邊使用 Mongodb演示

appsetting.json


"MongodbHost": {
"Connection": "mongodb://127.0.0.1:27017",
"DataBase": "Blog_Server",
"Table": ""
}

MongodbHostOptions.cs既然是面向對象的語言,最好是定義一個實體類

public class MongodbHostOptions
{
    /// <summary>
    /// 連接字符串
    /// </summary>
    public string Connection { get; set; }
    /// <summary>
    /// 庫
    /// </summary>
    public string DataBase { get; set; }
    /// <summary>
    /// 表
    /// </summary>
    public string Table { get; set; }
}

Startup.cs

// 首先 using 一下命名空間
using Microsoft.Extensions.Configuration;

// 后面的就是在 Startup 中的配置
...
public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    // MongodbHost信息  依賴注入一下,這樣就可以在別的 類 的構造函數中注入
    services.Configure<MongodbHostOptions>(Configuration.GetSection("MongodbHost"));

}
...

注入示例

// MongodbHost信息,類對象之下
private readonly MongodbHostOptions _mongodbHostOptions;

// 構造函數,注入一下
public BlogController(IOptions<MongodbHostOptions> mongodbHostOptions)
{
    _mongodbHostOptions = mongodbHostOptions.Value;
}

四. 完整工具類

using Oracle.ManagedDataAccess.Client;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Reflection;

namespace OracleHelper
{
public class OracleHelper
    {
        // 從 web.config 獲取
        private string connString = ConfigurationManager.ConnectionStrings["Conn_DB"].ToString();

        private static OracleHelper _instance;

        public static OracleHelper Instance
        {
            get
            {
                if (_instance == null)
                    _instance = new OracleHelper();
                return _instance;
            }
        }


        /// <summary>
        /// 查詢表數據(單表)
        /// </summary>
        /// <param name="sql">sql語句</param>
        /// <returns></returns>
        public static object GetData(string sql, int type)
        {
            try
            {
                using (OracleConnection conn = new OracleConnection(Instance.connString))
                {
                    OracleCommand cmd = new OracleCommand(sql, conn);
                    OracleDataAdapter adapter = new OracleDataAdapter(cmd);
                    DataSet ds = new DataSet();
                    adapter.Fill(ds);
                    return ds;                
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 執行sql 語句
        /// </summary>
        /// <param name="sql"></param>
        /// <returns>返回影響的行數</returns>
        public static int ExecuteNonQuery(string sql)
        {
            try
            {
                using (OracleConnection conn = new OracleConnection(Instance.connString))
                {
                    conn.Open();
                    OracleCommand cmd = new OracleCommand(sql, conn);
                    int row = cmd.ExecuteNonQuery();
                    conn.Close();
                    if (row > 0)
                    {
                        return row;
                    }
                }
            }
            catch (Exception e)
            {
                Console.Write(e);
            }
            return 0;
        }

        /// <summary>
        /// 執行sql List語句
        /// </summary>
        /// <param name="sqlText">需要執行的List</param>
        /// <returns>返回true/false</returns>
        public static bool ExeTransaction(List<string> sqlText)
        {
            using (OracleConnection conn = new OracleConnection(Instance.connString))
            {
                conn.Open();
                OracleTransaction tran = conn.BeginTransaction();
                try
                {

                    OracleCommand cmd = new OracleCommand();
                    cmd.Transaction = tran;
                    cmd.Connection = conn;
                    foreach (string item in sqlText)
                    {
                        cmd.CommandText = item;
                        cmd.ExecuteNonQuery();
                    }
                    tran.Commit();
                    return true;
                }
                catch (Exception ex)
                {
                    tran.Rollback();
                    throw ex;
                }
                finally
                {
                    conn.Close();
                }
            }
        }

    }
}

五. 控制台輸出

//多表多行多列的情況
foreach (DataTable dt in YourDataset.Tables)   //遍歷所有的datatable
{
    foreach (DataRow dr in dt.Rows)   ///遍歷所有的行
        foreach (DataColumn dc in dt.Columns)   //遍歷所有的列
            Console.WriteLine("{0},   {1},   {2}", dt.TableName, dc.ColumnName, dr[dc]);   //表名,列名,單元格數據
}
//遍歷一個表多行多列
foreach (DataRow mDr in dataSet.Tables[0].Rows)
{
    foreach (DataColumn mDc in dataSet.Tables[0].Columns)
    {
        Console.WriteLine(mDr[mDc].ToString());
    }
}
//遍歷一個表多行一列
foreach (DataRow row in DataSet1.Tables[0].Rows)
{
    Console.WriteLine(row[0].ToString());
}
//一行一列
ds.Tables[0].Rows[0]["字段"];

本文參考以下兩位大佬,感謝:
springsnow:https://www.cnblogs.com/springsnow/p/11393678.html
withJoy:https://www.cnblogs.com/xqz0618/p/Oracle.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM