ハイブリッドクラウドシナリオでSQL Serverを使用します。 パート2

原則として、匿名情報はパブリッククラウドに保存され、パーソナライズ部分はプライベートに保存されます。 これに関連して、疑問が生じます。ユーザーの要求に応じて単一の結果を生成するために、両方の部分をどのように結合するのでしょうか。 縦に分割された顧客テーブルがあるとします。 匿名列はWindows Azure SQLデータベースにあるテーブルに割り当てられますが、機密情報(フルネームなど)を持つ列はローカルSQL Serverに残ります。 両方のテーブルをキーCustomerIDにリンクする必要があります。 これらは異なるサーバー上の異なるデータベースにあるため、JOINでSQLステートメントを使用しても機能しません。 可能な解決策として、以前の記事で、ローカルSQL Serverでバインドが発生するシナリオを検討しました。 アプリケーションの一種のエントリポイントとして機能し、クラウドベースのSQL Serverはリンクされたものとして巻き上げられました。 この記事では、ローカルサーバーとクラウドサーバーの両方がアプリケーションに関して同等であり、データがその中で直接結合される場合、つまり、 ビジネスロジックのレベルで。



アプリケーションコードの観点からSQL Azureからデータをプルすることは、ローカルのSQL Serverでの作業と変わりません。 接続文字列に対して正確に言ってみましょう。 以下のコードでは、u1qgtaf85kはAzure SQL Serverの名前です(作成時に自動的に生成されます)。 TCP / IPネットワークライブラリ、ポート1433を介して接続が常に確立されることを思い出させてください。Trusted_Connection= Falseパラメーターは統合セキュリティではありません(SQL Azureでは常に標準です)。 -中間。



using System; using System.Data; using System.Data.SqlClient; using System.Diagnostics; using System.Resources; namespace DevCon2013 { class Program { static void Main(string[] args) { ResourceManager resMan = new ResourceManager("DevCon2013.Properties.Resources", System.Reflection.Assembly.GetExecutingAssembly()); string sqlAzureConnString = String.Format(@"Server=tcp:u1qgtaf85k.database.windows.net,1433;Database=AdventureWorks2012;User ID=alexejs;Password={0};Trusted_Connection=False;Encrypt=True", resMan.GetString("Password")); SqlConnection cnn = new SqlConnection(sqlAzureConnString); cnn.Open(); SqlCommand cmd = cnn.CreateCommand(); cmd.CommandText = "select top 100 CustomerID, AccountNumber from Sales.Customer order by CustomerID"; DataTable tbl = new DataTable(); tbl.Load(cmd.ExecuteReader()); cnn.Close(); foreach (DataRow r in tbl.Rows) { for (int i = 0; i < tbl.Columns.Count; i++) Debug.Write(String.Format("{0}\t", r[i])); Debug.WriteLine(""); } } } }
      
      





スクリプト1



ここに、オンプレミスリソースとの接続を追加します。 ローカルSQL Serverで。 あなたの許可があれば、このプロセスを説明する必要はないと想定します。そのため、ソースに接続してクエリを実行するExecuteSQLと、結果を視覚化するためのDumpTableの2つのメソッドを追加して、以前のコードを変更します。 したがって、アプリケーションの観点から見ると、SQL AzureとオンプレミスのSQL Serverは完全に対称的に動作します。



 string sqlOnPremiseConnString = @"Server=(local);Integrated Security=true;Database=AdventureWorks2012"; DataTable resultsOnPremise = ExecuteSQL(sqlOnPremiseConnString, "select BusinessEntityID, FirstName, LastName from Person.Person where BusinessEntityID between 1 and 100"); string sqlAzureConnString = String.Format(@"Server=tcp:u1qgtaf85k.database.windows.net,1433;Database=AdventureWorks2012;User ID=alexejs;Password={0};Trusted_Connection=False;Encrypt=True", resMan.GetString("Password")); DataTable resultsFromAzure = ExecuteSQL(sqlAzureConnString, "select CustomerID, AccountNumber from Sales.Customer where CustomerID between 1 and 100"); ... static DataTable ExecuteSQL(string cnnStr, string query) { SqlConnection cnn = new SqlConnection(cnnStr); cnn.Open(); SqlCommand cmd = cnn.CreateCommand(); cmd.CommandText = query; DataTable tbl = new DataTable(); tbl.Load(cmd.ExecuteReader()); cnn.Close(); return tbl; } static void DumpTable(DataTable tbl) { foreach (DataRow r in tbl.Rows) { for (int i = 0; i < tbl.Columns.Count; i++) Debug.Write(String.Format("{0}\t", r[i])); Debug.WriteLine(""); } }
      
      





スクリプト2



ここで、アプリケーション内に2つの垂直DataTableがある場合、両方の垂直[以前に統合されたCustomersテーブルの一部:ローカルサーバーから、SQL Azureから-現在存在するCustomerIDフィールドを使用してそれらを再度結合するために残ります。 簡単にするために、複合キーの場合、つまり 接続は、1つのテーブルの1つの列をある列から別の列に単純に等しくすることによって行われると想定しています。 これは古典的なADO.NETタスクです。 これを解決する最も一般的な方法は2つあり、パフォーマンスはほぼ同等です。 最初の方法は、DataRelationを使用する方法です。 JoinTablesADOメソッドで実装されます。 新しいDataSetを作成し、両方のラベルを追加し、それらの間にDataRelationを作成して、JOINが構築される親テーブルのフィールドと子テーブルのフィールドを示します。 2つのDataTableのどちらが親テーブルになり、どちらが子テーブルになるかは、この状況では重要ではありません。 私たちの場合、接続は1対多ではなく、1対1です。 結果のDataTableに空の空白を作成します。 「子」テーブルのすべてのレコードをループして、「親」テーブルの対応するレコードを取得し、両方のレコードDataRowのフィールドから結合して、結果のDataTableに入れます。



 DumpTable(JoinTablesADO(resultsFromAzure, resultsOnPremise, "CustomerID", "BusinessEntityID")); ... static DataTable JoinTablesADO(DataTable parentTbl, DataTable childTbl, string parentColName, string childColName) { DataSet ds = new DataSet(); ds.Tables.Add(parentTbl); ds.Tables.Add(childTbl); DataRelation dr = new DataRelation("-", parentTbl.Columns[parentColName], childTbl.Columns[childColName]); ds.Relations.Add(dr); DataTable joinedTbl = new DataTable(); foreach (DataColumn c in parentTbl.Columns) joinedTbl.Columns.Add(c.Caption, c.DataType); foreach (DataColumn c in childTbl.Columns) joinedTbl.Columns.Add(c.Caption, c.DataType); // ., Clone()  DataColumn   :( foreach (DataRow childRow in childTbl.Rows) { DataRow parentRow = childRow.GetParentRow("-"); DataRow currentRowForResult = joinedTbl.NewRow(); for (int i = 0; i < parentTbl.Columns.Count; i++) currentRowForResult[i] = parentRow[i]; for (int i = 0; i < childTbl.Columns.Count; i++) currentRowForResult[parentTbl.Columns.Count + i] = childRow[i]; joinedTbl.Rows.Add(currentRowForResult); } return joinedTbl; }
      
      





スクリプト3



2番目の方法はLinqを使用する方法です。 理論的には、すべてが最初のものと同じです。 実装の詳細の違い。 最初に、結果のテーブルを親構造のコピーとして作成します。 次に、子テーブルのフィールドをそれに追加します。 子のレコードのコレクションとの通信条件によって、親テーブルのレコードのコレクションに対するLinqクエリの結果として、レコードのコレクションを取得します。 その後、結果のテーブルに追加されます。



 DumpTable(JoinTablesLinq(resultsFromAzure, resultsOnPremise, "CustomerID", "BusinessEntityID")); ... static DataTable JoinTablesLinq(DataTable parentTbl, DataTable childTbl, string parentColName, string childColName) { DataTable joinedTbl = parentTbl.Clone(); var childColumns = childTbl.Columns.OfType<DataColumn>().Select(c => new DataColumn(c.ColumnName, c.DataType, c.Expression, c.ColumnMapping)); joinedTbl.Columns.AddRange(childColumns.ToArray()); var joinedTblRows = from parentRow in parentTbl.AsEnumerable() join childRow in childTbl.AsEnumerable() on parentRow.Field<int>(parentColName) equals childRow.Field<int>(childColName) select parentRow.ItemArray.Concat(childRow.ItemArray).ToArray(); foreach (object[] values in joinedTblRows) joinedTbl.Rows.Add(values); return joinedTbl; }
      
      





スクリプト4



All Articles