SqlDbTypeへの変換や推論がそれほど賢くない? その3

前回のつづき。

SqlParameterのDbTypeプロパティにDbType.Timeを設定したときの挙動がいまいちわかりづらいです。下のテストコードを見てください。Timeとして扱いたいのにDateTimeとして扱われてしまうのです。


[TestMethod]
public void TestTime()
{
// SqlDbTypeにTimeを指定。
// DbTypeはTimeのまま、SqlDbTypeはTimeになる。直観的に正しい。
var p = new SqlParameter
{
SqlDbType = SqlDbType.Time,
};
Assert.AreEqual(DbType.Time, p.DbType);
Assert.AreEqual(SqlDbType.Time, p.SqlDbType);

// ValueにTimeSpanを指定。
// CLRの型からDbTypeもSqlDbTypeもTimeに変換される。直感的に正しい。
p = new SqlParameter
{
Value = new TimeSpan()
};
Assert.AreEqual(DbType.Time, p.DbType);
Assert.AreEqual(SqlDbType.Time, p.SqlDbType);

// DbTypeにTimeを指定。
// DbTypeもSqlDbTypeもDateTimeに変換されてしまう。直感的でない!
p = new SqlParameter
{
DbType = DbType.Time,
};
Assert.AreEqual(DbType.DateTime, p.DbType);
Assert.AreEqual(SqlDbType.DateTime, p.SqlDbType);

// DbTypeにTimeを指定、さらにValueにTimeSpanを指定。
// DbTypeもSqlDbTypeもDateTimeに変換されてしまう。直感的でない!
p = new SqlParameter
{
DbType = DbType.Time,
Value = new TimeSpan()
};
Assert.AreEqual(DbType.DateTime, p.DbType);
Assert.AreEqual(SqlDbType.DateTime, p.SqlDbType);
}

この挙動は、パラメーターおよびパラメーターのデータ型の構成 (ADO.NET)に書かれていることに反している気がします。ドキュメントには、DbType.Timeを指定したらSqlDbType.Timeへの推論(変換)が行われるとしています。
ただ、ドキュメントには「SQL Server 2008のTime」とあり、SQL Serverにアクセスしていない上述のテストコードとはの挙動とは無関係のようにも思えます。でも、だったらこのドキュメントはなんのことを言っているんだ?(どこでの推論のことを言っているの?)ということになり、それはそれでよくわからないです。

いずれ、もう少し整理してMSに仕様を聞いてみようかな。他の型でも同じようなことがありそうですし。少なくともDbType.Dateを指定したときにも同じようにわかりづらい挙動をします。


public void TestDate()
{
// SqlDbTypeにDateを指定。
// DbTypeもSqlDbTypeもDate。直観的に正しい。
var p = new SqlParameter
{
SqlDbType = SqlDbType.Date,
};
Assert.AreEqual(DbType.Date, p.DbType);
Assert.AreEqual(SqlDbType.Date, p.SqlDbType);

// DbTypeにDateを指定。
// DbTypeもSqlDbTypeもDateTimeに変換されてしまう。直感的でない!
p = new SqlParameter
{
DbType = DbType.Date,
};
Assert.AreEqual(DbType.DateTime, p.DbType);
Assert.AreEqual(SqlDbType.DateTime, p.SqlDbType);
}

ちなみに以下の環境です。