1. 程式人生 > >\t\t在MSSQL中定義和使用C#自定義型別 SQL Server08表型別引數傳遞

\t\t在MSSQL中定義和使用C#自定義型別 SQL Server08表型別引數傳遞

在學習SQL Server 2008的過程中,突然發現SQL Server支援自定義表型別,我們可以輕鬆的將一個SQL Server 2008表型別作為引數傳遞給儲存過程。C#下實現了SQL Server 2008表型別引數傳遞

本示例中用到的型別在資料庫中的位置:
在MSSQL中定義和使用C自定義型別 SQL Server08表型別引數傳遞 - yandavid - 我的部落格
建立一個自定義表型別
CREATE TYPE [dbo].[UserDetailsType] AS TABLE
(
      [ID] [varchar](50) NULL,
      [Name] [varchar](50) NULL,
      [Sex] [varchar](50) NULL,
      [Age] [decimal](18, 0) NULL
)


建立一個名為User的表,結構如下:
在MSSQL中定義和使用C自定義型別 SQL Server08表型別引數傳遞 - yandavid - 我的部落格
建立一個儲存過程
CREATE PROCEDURE [dbo].[InsertUserInfo]
@UserInfo [UserDetailsType] readonly--指示不能在過程的主體中更新或修改引數。如果引數型別為使用者定義的表型別,則必須指定 READONLY
AS
BEGIN

insert into [User]
([ID], [Name], [Sex], [Age])
select [ID], [Name], [Sex], [Age]
from @UserInfo;

END

//啟動Visual Studio 2008,建立一個預設的窗體應用程式後,我們需要先在記憶體中建立一個數據庫表DataTable的例項,如下:
private static DataTable PrepareDatatable()
{
    DataTable dt = new DataTable("dt");
    DataColumn[] dtc = new DataColumn[4];
    dtc[0] = new DataColumn("ID", System.Type.GetType("System.String"));
    dtc[1] = new DataColumn("Name", System.Type.GetType("System.String"));
    dtc[2] = new DataColumn("Sex", System.Type.GetType("System.String"));
    dtc[3] = new DataColumn("Age", System.Type.GetType("System.Decimal"));
    dt.Columns.AddRange(dtc);
    return dt;
}

//然後,通過SqlCommand執行剛才我們建立的Test資料庫儲存過程InsertUserInfo,並傳遞我們在記憶體中建立的DataTable的例項,如下:
private static void SaveUserInfoDetails()
{
    DataTable dt = PrepareDatatable();
    for (int i = 0; i < = 5; i++)
    {
        DataRow dr = dt.NewRow();
        dr[0] = i.ToString();
        dr[1] = "Name" + i.ToString();
        dr[2] = "男";
        dr[3] = (i*10).ToString();
        dt.Rows.Add(dr);
    }
    using (SqlConnection conn = new SqlConnection("server=Rithia;database=Test;integrated security=SSPI"))
    {
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandType = System.Data.CommandType.StoredProcedure;
        cmd.CommandText = "dbo.InsertUserInfo";

        SqlParameter param = cmd.Parameters.AddWithValue("@UserInfo", dt);
        conn.Open();
        cmd.ExecuteNonQuery();
    }

}

通過上面的示例,我們可以在程式客戶端先建立好要傳遞的表型別資料,然後傳遞給儲存過程,而儲存過程則將SQL Server 2008表型別引數中的記錄一次性的新增到了資料庫實體表中,這種操作在需要傳遞給儲存過程陣列形式的引數時非常非常方便。

--------------原始做法:---------------------------------------------

using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;

namespace MyDBType
{
    [Serializable]//標記為是可序列化的
    [SqlUserDefinedType(Format.UserDefined, Name = "Person", MaxByteSize = 100)]
    /*
        SqlUserDefinedType特性支援以下屬性:

        Format——用語指定如何在SQL Server資料庫中序列化使用者自定義型別。其取值為Native和UserDefined;

        IsByteOrdered——用於使該自定義使用者型別按其本身的位元組表示方法排序;

        IsFixedLength——用於指定這個型別的所有例項是否都具有相同的長度;

        MaxByteSize——用於指定該使用者自定義型別的最大位元組數;

        Name——用於為使用者自定義型別指定名稱;

        ValidationMethodName——用於指定校驗使用者自定義型別是否有效的方法名稱。

        Format屬性最為重要,他自動使用者自定義型別如何進行序列化,選項設定為Native時是讓SQL Server資料庫自動處理所有序列化問題而不需要使用者做任何額外的操作。
                但原生序列化方式只能應用到簡單類上。如果類公開了非值型別的屬性(如String),那麼該類將不能使用原生序列化。
     */
    public class Person : IBinarySerialize, INullable
    {
        public string Name;
        public int Age;
        public char Sex;

        /// <summary>
        /// 在SQL查詢中對該屬性進行比較操作所必須指定的特性
        /// </summary>
        [SqlFacet(Precision = 38, Scale = 2)]
        public Decimal Account;

        #region IBinarySerialize 成員
        /// <summary>
        /// 用於從BinaryReader物件中讀取資料到類中的屬性
        /// </summary>
        /// <param name="r"></param>
        public void Read(System.IO.BinaryReader r)
        {
            string s = r.ReadString();
            string[] values = s.Split('|');
            Name = values[0];
            if (values.Length > 1) Int32.TryParse(values[1], out Age);
            if (values.Length > 2) Char.TryParse(values[2], out Sex);
            if (values.Length > 3) Decimal.TryParse(values[3], out Account);
        }

        /// <summary>
        /// 把類中的屬性寫入到BinaryReader物件
        /// </summary>
        /// <param name="w"></param>
        public void Write(System.IO.BinaryWriter w)
        {
            w.Write(string.Format("{0}|{1}|{2}|{3}", Name, Age.ToString(), Sex, Account));
        }

        #endregion

        #region INullable 成員
        /// <summary>
        /// 用於在sql中判斷該型別的變數是否為null
        /// </summary>
        public bool IsNull
        {
            get { return string.IsNullOrEmpty(Name); }
        }

        #endregion
        /// <summary>
        /// 實現靜態的返回型別為當前類型別的Null只讀屬性,返回一個在sql中認為為null的例項
        /// </summary>
        public static Person Null
        {
            get
            {
                return new Person { Name = string.Empty };
            }
        }
        /// <summary>
        /// 型別轉換函式
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static Person Parse(SqlString str)
        {
            string[] values = str.Value.Split('|');
            var p = new Person
                        {
                            Name = values[0],
                        };
            if (values.Length > 1) Int32.TryParse(values[1], out p.Age);
            if (values.Length > 2) Char.TryParse(values[2], out p.Sex);
            if (values.Length > 3) Decimal.TryParse(values[3], out p.Account);

            return p;
        }

        public override string ToString()
        {
            return this.IsNull ? "NULL" : string.Format("{0}|{1}|{2}|{3}", Name, Age.ToString(), Sex,Account);
        }
    }
}

---------SQL指令碼

select * from sys.assemblies

--引用該類所在的程式集

CREATE assembly MyType

from 'C:\MyDBType.dll'

go

--建立具體的型別 create type 型別名external name sql中程式集名.[C#類完全限定名]

CREATE TYPE person

external name MyType.[MyDBType.Person]

go

--建立以自定義型別為引數的儲存過程

create proc MyDBTypeTest

@p person

as

print @p.Name

go

--禁止在.Net Framewrok中執行使用者程式碼.啟用"clr enabled"配置選項

--Sql Server中執行這段程式碼可以開啟CLR

exec sp_configure'show advanced options', '1';

go

reconfigure;

go

exec sp_configure'clr enabled', '1'

go

reconfigure;

exec sp_configure'show advanced options', '1';

go

--定義變數

declare @p person

--賦值Parse(SqlString str) 函式派上用場了

set @p = convert(person ,N'David.Yan|30|n|100000.99')

PRINT @p.Account

--執行儲存過程

exec MyDBTypeTest@p

--弄個應該為null的值

set @p = convert(person, '|2|y')

--判斷是不是真為null;

if @p is null

print 'bool IsNull發揮作用了,static Person Null也發揮作用了.真為null'

/*

清理現場

drop proc MyDBTypeTest

drop type person

drop assembly MyType

*/

相關推薦

no