客先の旧システムで使用しているライブラリに、SQLServerに接続してDataSetを操作できるユーティリティークラスが作成されており、その資産を活かした簡易なO/Rマッパーが作れないか?との依頼がありました。
とりあえず、Entity Frameworkという便利なフレームワークがあるので、それを使いましょうと提案したんですが、あっさり断られ作ることになってしまいました。(Entity Frameworkは学習コストが高いらしく、旧システムの開発者でも簡単に使えるO/Rマッパーが必要なんだそうです。)
SQLServerのテーブルからC#のクラス定義を生成する処理を実装する時に、今まであまり深く考えていませんでしたが、テーブルの列に対応するC#のデータ型ってどうなるのかな?と思ったのでまとめてみました。
目次
使用するSQLServerのバージョン
SQLServerのバージョンは2017を使います。
使用するテーブル
データ型の一覧を取得するために、以下のテーブルを作成します。
T_ALL_COLUMNS
SQLServerのテーブルで指定できる全ての種類のデータ型の列を持つテーブルです。
| 列名 | データ型 |
|---|---|
| C_BIGINT | bigint |
| C_BINARY | binary(50) |
| C_BIT | bit |
| C_CHAR | char(10) |
| C_DATE | date |
| C_DATETIME | datetime |
| C_DATETIME2 | datetime2(7) |
| C_DATETIMEOFFSET | datetimeoffset(7) |
| C_DECIMAL | decimal(18, 0) |
| C_FLOAT | float |
| C_GEOGRAPHY | geography |
| C_GEOMETRY | geometry |
| C_HIERARCHYID | hierarchyid |
| C_IMAGE | image |
| C_INT | int |
| C_MONEY | money |
| C_NCHAR | nchar(10) |
| C_NTEXT | ntext |
| C_NUMERIC | numeric(18, 0) |
| C_NVARCHAR | nvarchar(50) |
| C_REAL | real |
| C_SMALLDATETIME | smalldatetime |
| C_SMALLINT | smallint |
| C_SMALLMONEY | smallmoney |
| C_SQL_VARIANT | sql_variant |
| C_TEXT | text |
| C_TIME | time(7) |
| C_TIMESTAMP | timestamp |
| C_TINYINT | tinyint |
| C_UNIQUEIDENTIFIER | uniqueidentifier |
| C_VARBINARY | varbinary(50) |
| C_VARCHAR | varchar(50) |
| C_XML | xml |
データ型を取得する
INFORMATION_SCHEMAで列情報を取得するSQL
|
1 2 3 4 5 6 7 |
select TABLE_NAME, COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS where TABLE_NAME = 'T_ALL_COLUMNS' |
SQLServerのシステムビューからテーブルの列情報を取得して変換しようと思ったんですが、そもそも変換先のデータ型がわからないので、できるわけがありません。
なので、SqlDataAdapterクラスのFillメソッドで、DataTableを取得してデータ型を確認することにします。
DataTableを取得するC#のコード
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/// <summary> /// SQLコネクションオブジェクトを作成するメソッド /// </summary> /// <returns></returns> private SqlConnection CreateConnection() { // Windows 認証で SQLServerに接続するための接続文字列 string connectionString = @"Data Source=サーバー名;Initial Catalog=データベース名;Integrated Security=True"; // SQL コネクションの作成 SqlConnection sqlConnection = new SqlConnection(connectionString); return sqlConnection; } /// <summary> /// データテーブルを取得するメソッド /// </summary> /// <returns></returns> public DataTable GetDataTable() { // テーブル名 string tableName = "T_ALL_COLUMNS"; // SQLコネクションオブジェクトを作成するメソッドを呼び出す SqlConnection sqlConnection = CreateConnection(); // SQLコマンドとSQLデータアダプターを使用してデータテーブルを取得 string cmdText = $"select * from dbo.{tableName}"; SqlCommand selectCommand = new SqlCommand(cmdText, sqlConnection); SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(selectCommand); DataTable dataTable = new DataTable(tableName); sqlDataAdapter.Fill(dataTable); return dataTable; } |
取得したデータテーブルのデータカラムをループしてColumnNameとDataTypeを取得した結果、以下のリストのようになりました。
データテーブルの列のデータ型
| ColumnName | DataType |
|---|---|
| C_BIGINT | System.Int64 |
| C_BINARY | System.Byte[] |
| C_BIT | System.Boolean |
| C_CHAR | System.String |
| C_DATE | System.DateTime |
| C_DATETIME | System.DateTime |
| C_DATETIME2 | System.DateTime |
| C_DATETIMEOFFSET | System.DateTimeOffset |
| C_DECIMAL | System.Decimal |
| C_FLOAT | System.Double |
| C_GEOGRAPHY | Microsoft.SqlServer.Types.SqlGeography |
| C_GEOMETRY | Microsoft.SqlServer.Types.SqlGeometry |
| C_HIERARCHYID | Microsoft.SqlServer.Types.SqlHierarchyId |
| C_IMAGE | System.Byte[] |
| C_INT | System.Int32 |
| C_MONEY | System.Decimal |
| C_NCHAR | System.String |
| C_NTEXT | System.String |
| C_NUMERIC | System.Decimal |
| C_NVARCHAR | System.String |
| C_REAL | System.Single |
| C_SMALLDATETIME | System.DateTime |
| C_SMALLINT | System.Int16 |
| C_SMALLMONEY | System.Decimal |
| C_SQL_VARIANT | System.Object |
| C_TEXT | System.String |
| C_TIME | System.TimeSpan |
| C_TIMESTAMP | System.Byte[] |
| C_TINYINT | System.Byte |
| C_UNIQUEIDENTIFIER | System.Guid |
| C_VARBINARY | System.Byte[] |
| C_VARCHAR | System.String |
| C_XML | System.String |
geography, geometry, hierarchyid型の列は、空間データ型を扱う際に使用されるMicrosoft.SqlServer.Types 名前空間のクラス、構造体として取得されるようです。
Entity FrameworkのData Model
参考までにEntity FrameworkのEntity Data Modelクラスを作成した場合の結果を載せておきます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
public partial class T_ALL_COLUMNS { public long C_BIGINT { get; set; } public byte[] C_BINARY { get; set; } public Nullable<bool> C_BIT { get; set; } public string C_CHAR { get; set; } public Nullable<System.DateTime> C_DATE { get; set; } public Nullable<System.DateTime> C_DATETIME { get; set; } public Nullable<System.DateTime> C_DATETIME2 { get; set; } public Nullable<System.DateTimeOffset> C_DATETIMEOFFSET { get; set; } public Nullable<decimal> C_DECIMAL { get; set; } public Nullable<double> C_FLOAT { get; set; } public System.Data.Entity.Spatial.DbGeography C_GEOGRAPHY { get; set; } public System.Data.Entity.Spatial.DbGeometry C_GEOMETRY { get; set; } public byte[] C_IMAGE { get; set; } public Nullable<int> C_INT { get; set; } public Nullable<decimal> C_MONEY { get; set; } public string C_NCHAR { get; set; } public string C_NTEXT { get; set; } public Nullable<decimal> C_NUMERIC { get; set; } public string C_NVARCHAR { get; set; } public Nullable<float> C_REAL { get; set; } public Nullable<System.DateTime> C_SMALLDATETIME { get; set; } public Nullable<short> C_SMALLINT { get; set; } public Nullable<decimal> C_SMALLMONEY { get; set; } public string C_TEXT { get; set; } public Nullable<System.TimeSpan> C_TIME { get; set; } public byte[] C_TIMESTAMP { get; set; } public Nullable<byte> C_TINYINT { get; set; } public Nullable<System.Guid> C_UNIQUEIDENTIFIER { get; set; } public byte[] C_VARBINARY { get; set; } public string C_VARCHAR { get; set; } public string C_XML { get; set; } } |
hierarchyid型と、sql_variant型には対応していないようで、生成時に除外されました。
これからO/Rマッパーの実装が佳境に入ります。
みなさん、O/Rマッパーの実装は、可能な限り避けましょう。