Asp.net C#に1つのデータテーブルがあります。そして、そのデータテーブルをPostgreSQL関数にテーブルパラメータとして渡します。どのようにして可能ですか?
以下の例は同じですが、SQL Serverにあります。同じことが必要ですが、問題はSQL ServerではなくPostgreSQLをバックエンドとして使用していることです。
はじめに
SQL Serverのストアドプロシージャは、パラメーターとしてSystem.Data.DataTableをサポートしています。 System.Data.SqlParameterクラスを使用して提供したのと同じ方法で、ADO.Netを使用してDataTableをストアドプロシージャに渡すことができますが、データ型にいくつかの変更が必要です。通常、次のコードのように、varchar、nvarchar、intなどの通常のパラメーターにSqlParameterのDbTypeを指定します。
SqlParameter sqlParam= new SqlParameter(); sqlParam.ParameterName = "@StudentName"; sqlParam.DbType = DbType.String; sqlParam.Value = StudentName;
ただし、テーブルパラメータの場合、パラメータデータタイプとしてDbTypeを指定する必要はありません。 DbTypeではなくSqlTypeを提供する必要があります。
例
SqlParameter Parameter = new SqlParameter; Parameter.ParameterName = "@PhoneBook"; Parameter.SqlDbType = SqlDbType.Structured; Parameter.Value = PhoneTable;
次の例では、電話帳のリストを受け取り、ADO.Netを使用してデータベースに保存します。この例では、リストから電話帳の詳細を取得してDataTableに格納し、このテーブルをパラメーターとしてNewPhoneBookという名前のストアドプロシージャに渡します。
//Phone book list List<PhoneBook> PhoneBooks //CReating Table DataTable PhoneTable = new DataTable(); // Adding Columns DataColumn COLUMN=new DataColumn(); COLUMN.ColumnName="ID"; COLUMN.DataType= typeof(int); PhoneTable.Columns.Add(COLUMN); COLUMN = new DataColumn(); COLUMN.ColumnName = "ContactNumber"; COLUMN.DataType = typeof(string); PhoneTable.Columns.Add(COLUMN); COLUMN = new DataColumn(); COLUMN.ColumnName = "ContactName"; COLUMN.DataType = typeof(string); PhoneTable.Columns.Add(COLUMN); // INSERTING DATA foreach (UserPhoneBook UPB in PhoneBooks) { DataRow DR = PhoneTable.NewRow(); DR[0] = UPB.UserName; DR[1] = UPB.ContactNumber; DR[2] = UPB.ContactName; PhoneTable.Rows.Add(DR); } //Parameter declaration SqlParameter[] Parameter = new SqlParameter[2]; Parameter[0].ParameterName = "@PhoneBook"; Parameter[0].SqlDbType = SqlDbType.Structured; Parameter[0].Value = PhoneTable; Parameter[1].ParameterName = "@Return_Value"; Parameter[1].Direction = ParameterDirection.ReturnValue; //Executing Procedure SqlHelper.ExecuteNonQuery(this.ConnectionString, CommandType.StoredProcedure, "[NewPhoneBook]", Parameter);
あなたはコードリファレンスを見つけることができます ここ
これらのオブジェクトは使用しません。彼らは単にそのように役に立たないようです。そうは言っても、PostgreSQLはjsonb
を介して関数にテーブルを渡すメソッドを持っています。 ストアドプロシージャへのテーブル値パラメーターの受け渡し で説明されている機能を取得したい場合は、それが理想的な解決策になるでしょう。 DataTableをJSONにマップして、JSONを関数に渡すだけです。
DatatableをJSONに変換するには、 JSON.net を使用できます。これらのスタックオーバーフローの回答もご覧ください。
Datatableが大きすぎてJSONにシリアル化できない場合は、DataRowオブジェクトをエクスポートするものの周りに外部データラッパーを作成する必要がある場合があります。これにより、 "DataReaderを使用したストリーミング行" 。サーバー/クライアントモデルが必要ない場合は、いつでもDataTableをCSVにダンプし、 Foreign Data Wrapper :で読み取ることで、ルートチェックを行うことができます。 out file-fdw 。
実際に試してみました。私はたくさんの問題に遭遇しました。
.NET Core 2.xでDataTableをJSONに変換し、
_using System;
using System.Data;
using Newtonsoft.Json;
class Program
{
static void Main()
{
// Get the DataTable.
DataTable table = GetTable();
// ... Use the DataTable here with SQL.
string json = JsonConvert.SerializeObject(table, Formatting.Indented);
Console.WriteLine(json);
}
static DataTable GetTable()
{
// Here we create a DataTable with four columns.
DataTable table = new DataTable();
table.Columns.Add("Dosage", typeof(int));
table.Columns.Add("Drug", typeof(string));
table.Columns.Add("Patient", typeof(string));
table.Columns.Add("Date", typeof(DateTime));
// Here we add five DataRows.
table.Rows.Add(25, "Indocin", "David", DateTime.Now);
table.Rows.Add(50, "Enebrel", "Sam", DateTime.Now);
table.Rows.Add(10, "Hydralazine", "Christoff", DateTime.Now);
table.Rows.Add(21, "Combivent", "Janet", DateTime.Now);
table.Rows.Add(100, "Dilantin", "Melanie", DateTime.Now);
return table;
}
}
_
それでもデータベースに接続してjsonをINSERT
ステートメントにドロップする必要がありますが、その は簡単に実行できるはずです。
_cmd.CommandText = "SELECT * FROM myfunc(@json)";
cmd.Parameters.AddWithValue("json", json);
_
サーバーでmyfunc(jsonb)
を定義すると、PostgreSQLにDataTable
が渡されます。
SQL Serverでできるのと同じ方法でPostgreSQLでそれを行うことができるとは思いません。とはいえ、内部で何が起こっているかを見ると、実際にシミュレーションすることはそれほど難しくありません。よくある誤解は、データテーブルがストアドプロシージャに「全体」渡されるというものです。そうではありません。データテーブルは、SQL Server側でデータテーブル内のデータを使用して再構築されます。 SQL Serverでこのアクションを実行すると、実際には次のようになります。
次のようになります。
DECLARE @p1 [dbo].[table_type_name];
INSERT INTO @p1 VALUES(...);
INSERT INTO @p1 VALUES(...);
-- continue until all rows have been inserted
EXEC [dbo].[sp_something] @dataTable = @p1;
何も特別なことはありません。一時テーブルまたはステージングテーブルを使用してこれをシミュレートし、SQLを自分で生成するのは簡単です。唯一の大きな違いは、テーブルへの参照をストアドプロシージャに渡すことができないことです。
Evanが述べたように、PostgreSQLにデータを渡す方法は他にもありますが、クロスプラットフォームソリューションを探している場合は、ANSI準拠のメソッドのみを選択する必要があります-残念ながら、これにはSQL Serverテーブル値パラメーターが含まれていません。
これは、ある種のステージングテーブルを必要とするソリューションを実装する方法です。
例:
[〜#〜] sql [〜#〜]
CREATE SEQUENCE seq_get_session_id START 1;
CREATE TABLE stg_table (
session_id bigint not null,
-- remainder of columns
);
CREATE OR REPLACE FUNCTION insert_data(_session_id BIGINT)
RETURNS void AS
$BODY$
BEGIN
INSERT INTO my_table (...)
SELECT /* columns */
FROM stg_table
WHERE session_id = _session_id;
DELETE FROM stg_table
WHERE session_id = _session_id;
END
$BODY$
LANGUAGE 'plpgsql' VOLATILE
COST 100;
C#
var phonebooks = GetPhoneBooks();
using (var connection = GetConnection())
{
long sessionId;
connection.Open();
var transaction = connection.BeginTransaction();
// get the session id
using(var command = connection.CreateCommand())
{
command.Transaction = transaction;
command.CommandText = "SELECT nextval('seq_get_session_id')";
using (var reader = command.ExecuteReader())
{
if (!reader.Read())
throw new InvalidOperationException("Unable to obtain session id");
sessionId = reader.GetInt64(0);
}
}
// insert data into staging table
using (var insertCommand = connection.CreateCommand())
{
insertCommand.CommandText =
"INSERT INTO stg_table (session_id, ...)" +
" VALUES (_session_id, ...)";
insertCommand.Transaction = transaction;
insertCommand.Parameters.AddWithValue("_session_id", sessionId);
var p1 = insertCommand.CreateParameter();
p1.ParameterName = "_p1";
p1.DbType = DbType.DateTime;
p1.Value = DateTime.Now;
insertCommand.Parameters.Add(p1);
// repeat above for each property that needs to be persisted...
foreach(var phonebook in phonebooks)
{
p1.Value = phonebook.Date;
// set values for any other parameters you have declared...
insertCommand.ExecuteNonQuery();
}
}
// execute final stored procedure to merge the data
using (var insertDataCommand = connection.CreateCommand())
{
insertDataCommand.CommandText = "insert_data";
insertDataCommand.CommandType = CommandType.StoredProcedure;
insertDataCommand.Parameters.AddWithValue("_session_id", sessionId);
insertDataCommand.Transaction = transaction;
insertDataCommand.ExecuteNonQuery();
}
transaction.Commit();
}
ただし、ステージングテーブルが必要ない場合、上記はmajor過剰です。ターゲットテーブルにデータを直接挿入できる場合は、上記のコードのほとんどを省略でき、これを行うだけです:
using (var connection = GetConnection())
{
connection.Open();
var transaction = connection.BeginTransaction();
using (var insertCommand = connection.CreateCommand())
{
insertCommand.CommandText =
"INSERT INTO my_table (...)" +
" VALUES (...)";
insertCommand.Transaction = transaction;
var p1 = insertCommand.CreateParameter();
p1.ParameterName = "_p1";
p1.DbType = DbType.DateTime;
p1.Value = DateTime.Now;
insertCommand.Parameters.Add(p1);
// repeat above for each property that needs to be persisted...
foreach(var phonebook in phonebooks)
{
p1.Value = phonebook.Date;
// set values for any other parameters you have declared...
insertCommand.ExecuteNonQuery();
}
}
transaction.Commit();
}
合格方法
データ表
POSTGRESQLのパラメーターとして
=================================================
POSTGREでデータテーブルとして渡すタイプテーブルを作成します
例…
私はpostgresqlで学生タイプを作成します
Type Student As(id integer、name text);
-==テスト用に物理テーブルを作成します。テーブルティーチャー(ID整数、名前テキスト)を作成します。
CREATE OR REPLACE FUNCTION public.usp_InsertStudent(ref1 refcursor、p_str_string json)RETURNS refcursor AS $ BODY $ BEGIN
Insert into Teacher (id,name)
select id,name from json_populate_recordset(null::Student,p_str_string);
OPEN REF1 FOR
select * from Teacher;
return ref1;
終わり; $ BODY $ LANGUAGE plpgsql VOLATILE COST 100;
C#からの呼び出し
DataSet ds = new DataSet(); DataTable table = new DataTable(); table.Columns.Add( "id"、typeof(int)); table.Columns.Add( "name"、typeof(string)); table.Rows.Add(25、 "ajay"); table.Rows.Add(25、 "rajesh"); table.Rows.Add(25、 "jayesh");
string json = JsonConvert.SerializeObject(table, Formatting.Indented);
string conStr = "put connection string here..";
NpgsqlConnection conn = new NpgsqlConnection(conStr);
conn.Open();
string query = string.Empty;
query = "select * from usp_InsertStudent('ref1'";
query = query + ",p_str_string:='"+json+"'"+
");fetch all in " + "\"ref1\";";
NpgsqlDataAdapter da = new NpgsqlDataAdapter(query, conn);
da.Fill(ds);
System.Data.DataTable dt = ds.Tables[1];
//// connect grid to DataTable
dataGridView1.DataSource = dt;
dataGridView1.DataBind();