Created
March 9, 2012 10:06
-
-
Save seraphy/2005926 to your computer and use it in GitHub Desktop.
ODP.NET/C# を使ってストアどプロシージャに一時BLOBデータを渡し方、およびユーザー定義型での受け渡し方のサンプル
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
create TYPE ATTACHED_FILE IS object( | |
FILE_NAME NVARCHAR2(256), | |
content blob | |
); | |
/ | |
CREATE OR REPLACE package ODP_BLOB_TEST | |
is | |
type ATTACHED_FILES is table of ATTACHED_FILE index by BINARY_INTEGER; | |
/** | |
* ファイル名とBLOBを受け取りファイルに出力する. | |
* 出力先ディレクトリはTEMP_DIRディレクトリオブジェクトが示す場所となる. | |
* TEMP_DIRというディレクトリオブジェクトが作成済みであり、 | |
* 読み書き権限が与えられていること. | |
*/ | |
procedure WRITE_BLOB(P_FILE_NAME in nvarchar2, P_BINARY in blob); | |
/** | |
* ファイル名とBLOBをユーザー定義タイプで受け取りファイルに出力する. | |
*/ | |
procedure WRITE_BLOB2(P_PARAM in ATTACHED_FILE); | |
/** | |
* ファイルへの出力テスト | |
*/ | |
procedure SELF_TEST; | |
end; | |
/ | |
CREATE OR REPLACE package body ODP_BLOB_TEST as | |
/** | |
* ファイル名とBLOBを受け取りファイルに出力する. | |
* 出力先ディレクトリはTEMP_DIRディレクトリオブジェクトが示す場所となる. | |
* TEMP_DIRというディレクトリオブジェクトが作成済みであり、 | |
* 読み書き権限が与えられていること. | |
*/ | |
procedure WRITE_BLOB(P_FILE_NAME in nvarchar2, P_BINARY in blob) as | |
VHANDLE UTL_FILE.FILE_TYPE; | |
BUF raw(1152); -- BASE64変換後のサイズ(読み込みバイトの1.5倍) | |
AMOUNT BINARY_INTEGER := 768; -- 48の倍数 (3と4で割り切れる数の1行単位); | |
POS PLS_INTEGER := 1; | |
BLOB_LEN PLS_INTEGER; | |
begin | |
VHANDLE := UTL_FILE.FOPEN('TEMP_DIR', P_FILE_NAME, 'wb'); | |
if P_BINARY is not null and p_file_name is not null then | |
BLOB_LEN := DBMS_LOB.GETLENGTH(P_BINARY); | |
WHILE POS < BLOB_LEN | |
LOOP | |
DBMS_LOB.read(P_BINARY, AMOUNT, POS, BUF); | |
UTL_FILE.PUT_RAW( | |
VHANDLE, | |
BUF, -- バイナリそのまま転送 | |
true | |
); | |
buf := NULL; | |
POS := POS + AMOUNT; | |
END LOOP; | |
UTL_FILE.FCLOSE(VHANDLE); | |
end if; | |
EXCEPTION when OTHERS then | |
UTL_FILE.FCLOSE(VHANDLE); | |
RAISE; | |
end WRITE_BLOB; | |
/** | |
* ファイル名とBLOBをユーザー定義タイプで受け取りファイルに出力する. | |
*/ | |
procedure WRITE_BLOB2(P_PARAM in ATTACHED_FILE) as | |
begin | |
WRITE_BLOB(P_PARAM.FILE_NAME, P_PARAM.content); | |
end WRITE_BLOB2; | |
/** | |
* ファイルへの出力テスト | |
*/ | |
procedure SELF_TEST as | |
lb blob; | |
ST timestamp; | |
EN timestamp; | |
-- 32Kを超えるバイナリデータをBLOB上に作成する | |
procedure generate_message(lb in out nocopy blob, cnt number) is | |
mes varchar2(4096); | |
rd raw(4096); | |
begin | |
for idx in 1..cnt | |
loop | |
mes := 'メッセージNo. ' || to_char(idx) || chr(10); | |
rd := UTL_I18N.STRING_TO_RAW(mes, 'UTF8'); | |
DBMS_LOB.WRITEAPPEND(lb, UTL_RAW.LENGTH(rd), rd); | |
end LOOP; | |
end; | |
begin | |
-- 一時BLOBを構築、寿命を呼び出しスコープに設定 | |
DBMS_LOB.CREATETEMPORARY(lb, TRUE, DBMS_LOB.CALL); | |
-- 32Kを超えるデータを作成 | |
generate_message(lb, 23456); | |
-- 長さの検証 | |
st := systimestamp; | |
DBMS_OUTPUT.PUT_LINE('len=' || DBMS_LOB.GETLENGTH(LB) || '/' || ST); | |
-- ファイルに書き出し | |
WRITE_BLOB('TEST.TXT', lb); | |
en := systimestamp; | |
dbms_output.put_line(en || '/span=' || (en - st)); | |
-- 一時LOBの破棄 | |
DBMS_LOB.FREETEMPORARY(lb); | |
end; | |
end ODP_BLOB_TEST; | |
/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Configuration; | |
using System.Data; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using Oracle.DataAccess.Client; | |
using Oracle.DataAccess.Types; | |
namespace odptest | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
// コネクション | |
string connStr = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; | |
using (var conn = new OracleConnection(connStr)) | |
{ | |
conn.Open(); | |
// ODP_BLOB_TEST.WRITE_BLOBメソッドを呼び出しを繰り返す | |
foreach (var idx in Enumerable.Range(0, 10)) | |
{ | |
var fileName = string.Format("TEST-A-{0}.txt", idx); | |
WriteBlob(conn, fileName); | |
} | |
// ODP_BLOB_TEST.WRITE_BLOB2メソッドを呼び出しを繰り返す | |
foreach (var idx in Enumerable.Range(0, 10)) | |
{ | |
var fileName = string.Format("TEST-B-{0}.txt", idx); | |
WriteBlob2(conn, fileName); | |
} | |
conn.Clone(); | |
} | |
} | |
/// <summary> | |
/// コネクションに関連づけられた一時Blobを作成しテストデータを設定して返す. | |
/// コネクションはオープンされていなければならない. | |
/// (コネクションが閉じられることでBlobは無効となる.) | |
/// </summary> | |
/// <param name="conn">コネクション</param> | |
/// <returns>テストデータ設定済みの一時Blob</returns> | |
static OracleBlob MakeBlob(OracleConnection conn) | |
{ | |
// コネクションがオープンされている状態でコンストラクタにより | |
// 一時Blobとして構築することができる. | |
var blob = new OracleBlob(conn); | |
// BLOBデータを作成する. | |
var enc = System.Text.Encoding.UTF8; | |
foreach (var idx in Enumerable.Range(0, 2000)) | |
{ | |
string mes = string.Format( | |
"Hello, World! {0}:{1:yyyy/MM/dd hh:mm:ss}\r\n", | |
idx, | |
DateTime.Now | |
); | |
byte[] buf = enc.GetBytes(mes); | |
// リモートにデータが送り込まれる | |
blob.Append(buf, 0, buf.Length); | |
} | |
// リワインド | |
blob.Position = 0; | |
return blob; | |
} | |
/// <summary> | |
/// ODP_BLOB_TEST.SEND_BLOBメソッドを呼び出す. | |
/// </summary> | |
/// <param name="conn">コネクション</param> | |
/// <param name="fileName">ファイル名</param> | |
static void WriteBlob(OracleConnection conn, string fileName) | |
{ | |
using (OracleBlob blob = MakeBlob(conn)) | |
{ | |
using (var cmd = new OracleCommand()) | |
{ | |
cmd.Connection = conn; | |
cmd.CommandText = "begin ODP_BLOB_TEST.WRITE_BLOB(:FILE_NAME, :DATA); end;"; | |
cmd.CommandType = System.Data.CommandType.Text; | |
cmd.BindByName = true; | |
var param1 = new OracleParameter("FILE_NAME", OracleDbType.NVarchar2); | |
param1.Direction = System.Data.ParameterDirection.Input; | |
param1.Value = fileName; | |
cmd.Parameters.Add(param1); | |
var param2 = new OracleParameter("DATA", OracleDbType.Blob); | |
param2.Direction = System.Data.ParameterDirection.Input; | |
param2.Value = blob; | |
cmd.Parameters.Add(param2); | |
cmd.ExecuteNonQuery(); | |
} | |
blob.Close(); | |
} | |
} | |
/// <summary> | |
/// ODP_BLOB_TEST.SEND_BLOBメソッドを呼び出す. | |
/// </summary> | |
/// <param name="conn">コネクション</param> | |
/// <param name="fileName">ファイル名</param> | |
static void WriteBlob2(OracleConnection conn, string fileName) | |
{ | |
using (OracleBlob blob = MakeBlob(conn)) | |
{ | |
using (var cmd = new OracleCommand()) | |
{ | |
cmd.Connection = conn; | |
cmd.CommandText = "begin ODP_BLOB_TEST.WRITE_BLOB2(:ATTACHED_FILE); end;"; | |
cmd.CommandType = System.Data.CommandType.Text; | |
cmd.BindByName = true; | |
var attachedFile = new AttachedFile(); | |
attachedFile.FileName = fileName; | |
attachedFile.Content = blob; | |
var param1 = new OracleParameter("ATTACHED_FILE", OracleDbType.Object); | |
param1.Direction = System.Data.ParameterDirection.Input; | |
param1.UdtTypeName = "ODPNET.ATTACHED_FILE"; | |
param1.Value = attachedFile; | |
cmd.Parameters.Add(param1); | |
cmd.ExecuteNonQuery(); | |
} | |
blob.Close(); | |
} | |
} | |
} | |
/// <summary> | |
/// CREATE TYPE IS ATTACHED_FILE IS OBJECT(FILE_NAME VARCHAR2, CONTENT BLOB); | |
/// のユーザー定義型に対するODP.NETのカスタム型の定義 | |
/// </summary> | |
public class AttachedFile : IOracleCustomType, INullable | |
{ | |
/// <summary> | |
/// フィールド名: FILE_NAME | |
/// </summary> | |
public const string KEY_FILE_NAME = "FILE_NAME"; | |
// フィールド名: CONTENT | |
public const string KEY_CONTENT = "CONTENT"; | |
/// <summary> | |
/// FILE_NAME属性 | |
/// </summary> | |
[OracleObjectMapping(KEY_FILE_NAME)] | |
public string FileName { set; get; } | |
/// <summary> | |
/// CONTENT属性 | |
/// </summary> | |
[OracleObjectMapping(KEY_CONTENT)] | |
public OracleBlob Content { set; get; } | |
// INullable | |
public bool IsNull | |
{ | |
get | |
{ | |
return string.IsNullOrWhiteSpace(FileName) && Content == null; | |
} | |
} | |
// INullable | |
public static AttachedFile Null | |
{ | |
get | |
{ | |
return new AttachedFile(); | |
} | |
} | |
// IOracleCustomType | |
public void ToCustomObject(OracleConnection conn, IntPtr pUdt) | |
{ | |
FileName = OracleUdt.GetValue(conn, pUdt, KEY_FILE_NAME) as string; | |
Content = OracleUdt.GetValue(conn, pUdt, KEY_CONTENT) as OracleBlob; | |
} | |
// IOracleCustomType | |
public void FromCustomObject(OracleConnection con, IntPtr pUdt) | |
{ | |
OracleUdt.SetValue(con, pUdt, KEY_FILE_NAME, FileName); | |
OracleUdt.SetValue(con, pUdt, KEY_CONTENT, Content); | |
} | |
// Object | |
public override string ToString() | |
{ | |
return FileName + ":" + Content; | |
} | |
} | |
/// <summary> | |
/// ODPNET.ATTACHED_FILE ユーザー定義オブジェクト型のマッピング定義. | |
/// </summary> | |
[OracleCustomTypeMapping("ODPNET.ATTACHED_FILE")] | |
public class AttachedFileFactory : IOracleCustomTypeFactory | |
{ | |
// IOracleCustomTypeFactory | |
public IOracleCustomType CreateObject() | |
{ | |
return new AttachedFile(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment