by WebSurfer
2014年5月30日 16:37
SQL Server の接続文字列で Initial Catalog(データベース名)の指定は必要かという話を書きます。
MSDN ライブラリなどでは、SQL Server の既定のインスタンスまたは名前つきインスタンスに接続する場合の接続文字列(正確には SqlClient 接続文字列)の例として、Initail Catalog(もしくは Database)キーワードでデータベース名を指定するように書かれています。
具体例は下記のページを見てください。
Initial Catalog(もしくは Database)のない接続文字列の例は、自分が知る限りですが、見たことがないです。
なので、接続文字列にデータベース名の指定は必須かと思い込んでいましたが、ある機会に試してみたところ、そんなことはなかったです。
以下の条件が満足されれば、任意のデータベースからデータを取得できます。
-
SQL Server の既定のインスタンスまたは名前つきインスタンスが対象。(ユーザーインスタンスとか LacalDB など、.mdf ファイルを動的にアタッチするようなケースはダメです)
-
同一インスタンス内にある、静的にアタッチ済みのデータベースを対象とする。
-
接続文字列で指定したログイン権限で SQL Server による認証が通ってログインできること。
-
接続文字列にデータベース名の指定がない場合、もしくは指定されていてもそれとは異なるデータベースを対象とする場合は、データベース名を特定できるクエリを記述する。例えば、 [データベース名].[スキーマ名].[テーブル名] というように。
-
ログインしたユーザーが、目的のデータベースに対して必要な権限を持っている(すなわち、SQL Server によるユーザー承認が通る)。具体的には、先の記事 ユーザー権限の設定 に書いたような設定がしてあることが条件です。
ADO.NET のコードを使って説明した方が分かりやすいと思いますので、以下にサンプルをアップしておきます。説明はコメントに書きましたので見てください。
using System;
using System.Data.SqlClient;
class Program
{
static void Main(string[] args)
{
// Initial Catalog=PUBS でも NORTHWIND から取得できる。
// Initial Catalog の指定なしでも OK。下はその例。
// ただしクエリに DB 名の指定が必要。下の例を参照。
// Integrated Security=True まで省くとログインできない。
string connString1 =
"Data Source=tcp:papiko-pc;Integrated Security=True";
string query1 =
"SELECT CategoryID, CategoryName " +
"FROM [NORTHWIND].[dbo].[Categories];" +
"SELECT EmployeeID, LastName " +
"FROM [NORTHWIND].[dbo].[Employees]";
RetrieveMultipleResults(new SqlConnection(connString1), query1);
// Initial Catalog を指定すればクエリで DB 名の指定は不要(下
// の例では NORTHWIND に含まれる Categories テーブル)。
// ただし、titleauthor テーブルは PUBS に含まれるものなので、
// 下の例のようにクエリに DB 名の指定が必要。
string connString2 =
"Data Source=tcp:papiko-pc;Initial Catalog=NORTHWIND;" +
"Integrated Security=True";
string query2 =
"SELECT CategoryID, CategoryName FROM Categories;" +
"SELECT royaltyper, au_id FROM [PUBS].[dbo].[titleauthor]";
RetrieveMultipleResults(new SqlConnection(connString2), query2);
}
// MSDN ライブラリ「DataReader によるデータの取得」
// http://msdn.microsoft.com/ja-jp/library/haa3afyz.aspx
// NextResult による複数の結果セットの取得
static void RetrieveMultipleResults(
SqlConnection connection, string query)
{
using (connection)
{
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.HasRows)
{
Console.WriteLine("\t{0}\t{1}", reader.GetName(0),
reader.GetName(1));
while (reader.Read())
{
Console.WriteLine("\t{0}\t{1}",
reader.GetInt32(0), reader.GetString(1));
}
// バッチ Transact-SQL ステートメントの結果を読み込む
// ときに、データリーダーを次の結果に進めます。
reader.NextResult();
}
}
}
}
よく分からないのは、上記のようなことができるのに、何のためにデータベース名を接続文字列に指定するかということです。
クエリを書くときにデータベース名を省略できるぐらいのメリットしか思い浮かびません。他に、コードファーストを利用する際 Initial Catalog に指定された名前でデータベースを作ってくれるということもあるそうですが。でも、そんな理由ではなさそうです。
接続プールが複数作られることになるのも無駄なような気がします。(Initial Catalog が違えばもちろん、キーワードを異なる順序で指定しただけでも接続プールは異なるとのこと。詳しくは MSDN ライブラリ SQL Server の接続プール (ADO.NET) を参照)
上のサンプルの結果からわかるように、接続プールは接続文字列で指定されるインスタンスに接続するためにあるだけで、インスタンス中にあるどのデータベースに接続するかは関知しないです。
それなのに、わざわざ接続文字列にデータベースを指定して、複数の接続プールを作る理由が分かりません。
そもそも、同じ接続プールで複数の異なるデータベースに接続するなどということはやってはいけないことで、好ましからざる副作用があるのでしょうか?
by WebSurfer
2014年4月18日 17:15
IUSR は固定ではなく変更できるという話です。何を今さらといわれるかもしれませんはが、実は、自分は最近まで知らなかったです。(汗)
IUSR とは、先の記事 ASP.NET の ID オブジェクト で書きましたように、匿名アクセスの際に IIS によって使用されるデフォルトの ID です。
これを上の画像のように、特定のユーザーアカウントやアプリケーションプールの ID に変更することができます。詳しい手順は IIS のホームの記事 Anonymous Authentication を見てください。
ASP.NET ベースの Web アプリケーションの場合は、自分が知る限りですが、匿名ユーザー ID の変更が必要になるようなケースはなかったので、IUSR を変更するということは考えもしませんでした。
しかし、PHP アプリケーションを IIS でホストする場合、TexhNet のライブラリ FastCGI を使用して IIS 7 で PHP アプリケーションをホストする の「FastCGI および PHP の構成に関するベスト プラクティス」のセクションに書いてあるように、アプリケーションプール ID を使用するよう匿名ユーザー ID を構成することが推奨されているようです。
それ以外に IUSR を変更することが推奨されているケースがあるかどうかは分かりませんけど、一応変えられるということだけ備忘録として書いておきます。
by WebSurfer
2014年4月5日 15:47
Ajax Control Toolkit の ModalPopupExtender をドラッグできない(正確には、ドラッグはできるが元の位置に戻ってしまう)ケースがあります。その理由と対処法を書きます。
検証用に、上の画像のような Button コントロールを一つだけ配置したような aspx ページを作ったとします。
Button クリックで ModalPopup が現れ、デフォルトではウィンドウの中央に表示されるはずです。
これをマウスでクリックして任意の位置にドラッグすることができますが、離すと元の位置に戻ってしまいます。
その理由は、ModalPopup のドラッグが有効なのは body の中だけなので、ボタン一つだけというように body のサイズが極端に小さくなる場合、ドラッグしても元の位置に戻ってしまうということになります。
通常はボタン一つだけというようなページを作ることはないので、このような問題に遭遇することはないかもしれませんが、もし body のサイズが極端に小さくなる場合があれば、CSS で body のサイズを指定してやることで問題を回避できます。
上の画像のサンプルは、実際に動かして試すことができるよう 実験室 にアップしましたが、これは body に height: 300px; width: 600px; というスタイルを適用しています。
height: 300px; width: 600px; の範囲(赤い線で囲った部分)内だけでドラッグして移動できる(範囲外にドラッグした場合は元の位置に戻ってしまう)ことが分かりますので、興味のある方は試してみてください。
サンプルのコードは以下の通りです。
<%@ Page Language="C#" %>
<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit" TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>WebSurfer's Page - 実験室</title>
<style type="text/css">
.modalBackground {
background-color: Gray;
filter: alpha(opacity=70);
opacity: 0.7;
}
.modalPopup {
height: 150px;
width: 400px;
background-color: White;
}
.modalDraggableArea {
cursor: move;
background-color: #DDDDDD;
border: solid 1px Gray;
}
body {
height: 300px;
width: 600px;
border: 1px solid red;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<asp:ToolkitScriptManager ID="Manager1" runat="server">
</asp:ToolkitScriptManager>
<asp:ModalPopupExtender ID="ModalPopupExtender1"
runat="server"
TargetControlID="Button1"
PopupControlID="Panel1"
PopupDragHandleControlID="Panel2"
BackgroundCssClass="modalBackground"
OkControlID="Button2"
CancelControlID="Button3">
</asp:ModalPopupExtender>
<asp:Button ID="Button1"
runat="server" Text="ModalPopup 表示" />
<asp:Panel ID="Panel1"
runat="server"
CssClass="modalPopup">
<asp:Panel ID="Panel2"
runat="server"
CssClass="modalDraggableArea">
<p style="text-align: center;">
********* ここをつかんでドラッグ *********
</p>
</asp:Panel>
<p style="text-align: center;">ModalPopup</p>
<p style="text-align: center;">
<asp:Button ID="Button2" runat="server" Text="OK" />
<asp:Button ID="Button3" runat="server" Text="Cancel" />
</p>
</asp:Panel>
</form>
</body>
</html>