1. 程式人生 > >原 SQL Server基礎(十) VS2015 連線資料庫——進階篇:資料庫事務

原 SQL Server基礎(十) VS2015 連線資料庫——進階篇:資料庫事務

一、簡介

什麼是資料庫事務?假如一個數據有多個表,我們希望刪除A表的A1記錄,那麼B表就會對應地增加對應的B1記錄,從而保證資料的完整性與一致性。

比如:

參考:

二、往AutoLot新增一張CreditRisks表

CreditRisks表將記錄Customers表不誠信的使用者。

三、新增方法

類庫用上一篇部落格,新增方法ProcessCreditRisk即可。

        /// <summary>
        /// 事務處理
        /// </summary>
        /// <param name="throwEx"></param>
        /// <param name="custID"></param>
        public void ProcessCreditRisk(bool throwEx, int custID)
        {
            //根據使用者ID查詢不守信用的使用者名稱
            string fName = string.Empty;
            string lName = string.Empty;
            SqlCommand cmdSelect = new SqlCommand(
              string.Format("Select * from Customers where CustID = {0}", custID), sqlConnection);
            using (SqlDataReader dr = cmdSelect.ExecuteReader())
            {
                if (dr.HasRows)
                {
                    dr.Read();
                    fName = (string)dr["FirstName"];
                    lName = (string)dr["LastName"];
                }
                else
                    return;
            }

            //建立刪除或新增的命令物件
            SqlCommand cmdRemove = new SqlCommand(
              string.Format("Delete from Customers where CustID = {0}", custID), sqlConnection);

            SqlCommand cmdInsert = new SqlCommand(string.Format("Insert Into CreditRisks" +
                             "(CustID, FirstName, LastName) Values" +
                             "({0}, '{1}', '{2}')", custID, fName, lName), sqlConnection);

            // We will get this from the connection object.
            SqlTransaction tx = null;
            try
            {
                tx = sqlConnection.BeginTransaction();

                // Enlist the commands into this transaction.
                cmdInsert.Transaction = tx;
                cmdRemove.Transaction = tx;

                // Execute the commands.
                cmdInsert.ExecuteNonQuery();
                cmdRemove.ExecuteNonQuery();

                // 模擬錯誤
                if (throwEx)
                {
                    throw new Exception("Sorry!  Database error! Tx failed...");
                }

                //提交事物
                tx.Commit();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                //有任何錯誤都會回滾事物。
                tx.Rollback();
            }
        }

四、C#工程

C#工程用上一篇部落格,新增 GetProcessCreditRisk方法即可

program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using AutoLotConnectedLayer;
//using System.Data;
using System.Configuration;
using System.Data;

namespace AutoLotGUIclient
{
    class Program
    {
        static void Main(string[] args)
        {
            string cnStr = ConfigurationManager.ConnectionStrings["AutoLotSqlProvider"].ConnectionString;
            bool userDone = false;
            string userCommand = "";

            //建立InventoryDAL物件。
            InventoryDAL invDAL = new InventoryDAL();
            //開啟資料連線
            invDAL.OpenConnection(cnStr);
    
            try
            {
                ShowInstructions();
                do
                {
                    Console.Write("\nPlease enter your command: ");
                    //輸入指令
                    userCommand = Console.ReadLine();
                    Console.WriteLine("你剛才輸入的字母已經被轉為大寫:{0}", userCommand.ToUpper());
                    Console.WriteLine();
                    switch (userCommand.ToUpper())
                    {
                        case "I":
                            InsertNewCar(invDAL);
                            break;
                        case "U":
                            UpdateCarPetName(invDAL);
                            break;
                        case "D":
                            DeleteCar(invDAL);
                            break;
                        case "L":
                            // ListInventory(invDAL);
                            ListInventoryViaList(invDAL);
                            break;
                        case "S":
                            ShowInstructions();
                            break;
                        case "P":
                            LookUpPetName(invDAL);
                            break;
                        case "TX":
                            GetProcessCreditRisk(invDAL);
                            break;
                        case "Q":
                            userDone = true;
                            break;
                        default:
                            Console.WriteLine("Bad data!  Try again");
                            break;
                    }
                } while (!userDone);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            finally
            {
                invDAL.CloseConnection();
            }
        }

        #region Show instructions
        private static void ShowInstructions()
        {

            Console.WriteLine("I: Inserts a new car.");
            Console.WriteLine("U: Updates an existing car.");
            Console.WriteLine("D: Deletes an existing car.");
            Console.WriteLine("L: Lists current inventory.");
            Console.WriteLine("S: Shows these instructions.");
            Console.WriteLine("P: Looks up pet name.");
            Console.WriteLine("TX: 處理事物.");
            Console.WriteLine("Q: Quits program.");
        }

        #endregion

        #region List inventory
        private static void ListInventory(InventoryDAL invDAL)
        {
            // Get the list of inventory.
            DataTable dt = invDAL.GetAllInventoryAsDataTable();
            DisplayTable(dt);
        }

        private static void ListInventoryViaList(InventoryDAL invDAL)
        {
            // Get the list of inventory.
            List<NewCar> record = invDAL.GetAllInventoryAsList();

            foreach (NewCar c in record)
            {
                Console.WriteLine("CarID: {0}, Make: {1}, Color: {2}, PetName: {3}",
                    c.CarID, c.Make, c.Color, c.PetName);
            }
        }

        private static void DisplayTable(DataTable dt)
        {
            // Print out the column names.
            for (int curCol = 0; curCol < dt.Columns.Count; curCol++)
            {
                Console.Write(dt.Columns[curCol].ColumnName + "\t");
            }
            Console.WriteLine("\n----------------------------------");

            // Print the DataTable.
            for (int curRow = 0; curRow < dt.Rows.Count; curRow++)
            {
                for (int curCol = 0; curCol < dt.Columns.Count; curCol++)
                {
                    Console.Write(dt.Rows[curRow][curCol].ToString() + "\t");
                }
                Console.WriteLine();
            }
        }

        #endregion

        #region Delete car
        private static void DeleteCar(InventoryDAL invDAL)
        {
            // Get ID of car to delete.
            Console.Write("Enter ID of Car to delete: ");
            int id = int.Parse(Console.ReadLine());

            // Just in case we have a primary key
            // violation!
            try
            {
                invDAL.DeleteCar(id);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
        #endregion

        #region Insert car
        private static void InsertNewCar(InventoryDAL invDAL)
        {
            // First get the user data.
            int newCarID;
            string newCarColor, newCarMake, newCarPetName;

            Console.Write("Enter Car ID: ");
            newCarID = int.Parse(Console.ReadLine());
            Console.Write("Enter Car Color: ");
            newCarColor = Console.ReadLine();
            Console.Write("Enter Car Make: ");
            newCarMake = Console.ReadLine();
            Console.Write("Enter Pet Name: ");
            newCarPetName = Console.ReadLine();

            // Now pass to data access library.
            // invDAL.InsertAuto(newCarID, newCarColor, newCarMake, newCarPetName);
            NewCar c = new NewCar
            {
                CarID = newCarID,
                Color = newCarColor,
                Make = newCarMake,
                PetName = newCarPetName
            };
            invDAL.InsertAuto(c);
        }
        #endregion

        #region Update pet name
        private static void UpdateCarPetName(InventoryDAL invDAL)
        {
            // First get the user data.
            int carID;
            string newCarPetName;

            Console.Write("Enter Car ID: ");
            carID = int.Parse(Console.ReadLine());
            Console.Write("Enter New Pet Name: ");
            newCarPetName = Console.ReadLine();

            // Now pass to data access library.
            invDAL.UpdateCarPetName(carID, newCarPetName);
        }

        #endregion

        #region Look up name
        private static void LookUpPetName(InventoryDAL invDAL)
        {
            // Get ID of car to look up.
            Console.Write("Enter ID of Car to look up: ");
            int id = int.Parse(Console.ReadLine());
            Console.WriteLine("Petname of {0} is {1}.",
              id, invDAL.LookUpPetName(id).TrimEnd());
        }
        #endregion

        public static void GetProcessCreditRisk(InventoryDAL invDAL)
        {
            //bool throwEx = true;//無法從表Customers刪除客戶3,且無法新增該使用者到表CreditRisks
            bool throwEx = false;//從表Customers刪除客戶3,且新增該使用者到表CreditRisks
            invDAL.ProcessCreditRisk(throwEx, 3);
        }
    }
}

五、輸出結果

刪除Customers的第三行之前:

刪除中:

刪除後,Customers表少了一行,CreditRisks多了一行:

五、總結

至此,21章的學習,告一段落。