(C#)C# ORM - Dapper
C#のORMというと標準の Entity Framework があるが、
「遅い」、「学習コストが高い」などというのがあるそうだ。
それにやっぱりSQLは生で書くことが多い。
「C# ORM」で検索すると Entity Framework と Dapper がよくヒットする。
ということで Dapper を使ってみるとすごく手に馴染んだ。
以下、 Dapper を使っているコードと、動作確認ソース。
Dapper使用コード
using System; using System.Collections.Generic; using System.Configuration; using System.Data.SqlClient; using Dapper; namespace LibraryDapper.DBNS { /// <summary> /// データベース関係クラス /// </summary> class DB { /// <summary> /// Privateコンストラクタ /// </summary> private DB() { } public static string GetConnectionString() { return ConfigurationManager.ConnectionStrings["sqlsvr"].ConnectionString; } /// <summary> /// SQL SELECT文実行 /// </summary> /// <param name="sql">SQL文字列</param> /// <returns>SELECT検索結果</returns> public static IEnumerable<dynamic> ExecuteQuery(string sql, object parameter = null) { dynamic result; // 接続文字列の取得 var connectionString = GetConnectionString(); using (var connection = new SqlConnection(connectionString)) { try { connection.Open(); // SQLの実行(これがDapperのメソッド) result = connection.Query(sql, parameter); } catch (Exception exception) { Console.WriteLine(exception.Message); throw; } finally { connection.Close(); } } return result; } /// <summary> /// SQL(INSERT/UPDATE/DELETE)実行 /// </summary> /// <param name="sql">SQL文字列</param> public static int ExecuteNonQuery(List<string> sqlList, List<Object> targetList) { int affected = 0; // 接続文字列の取得 var connectionString = GetConnectionString(); // DBコネクション var connection = new SqlConnection(connectionString); SqlTransaction transaction = null; try { connection.Open(); // トランザクション開始 transaction = connection.BeginTransaction(); for (var i = 0; i < sqlList.Count; i++) { // SQLの実行(これがDapperのメソッド) affected += connection.Execute(sqlList[i], targetList[i], transaction); // これがDapperのメソッド } // コミット transaction.Commit(); } catch (Exception exception) { Console.WriteLine(exception.Message); // ロールバック transaction.Rollback(); throw; } finally { transaction.Dispose(); connection.Close(); } return affected; } } }
動作確認コード
using System; using System.Collections.Generic; using System.Data; using System.Linq; using LibraryDapper.DBNS; using LibraryDapper.LibraryNS; namespace LibraryDapper { class Program { static void Main(string[] args) { Console.WriteLine("DBアクセス サンプル"); Console.WriteLine("--- INSERT サンプル"); Insert(); Console.WriteLine("--- SELECT サンプル"); Select(); Console.WriteLine("--- UPDATE サンプル"); Update(); Console.WriteLine("--- DELETE サンプル"); Delete(); } /// <summary> /// SQL Select サンプル /// </summary> static void Select() { // Authors検索結果 var authors = DB.ExecuteQuery(@"SELECT * FROM AUTHORS"); // Books検索結果 var books = DB.ExecuteQuery(@"SELECT * FROM BOOKS"); var bookList = books.OrderBy(b => b.Id) .Select(b => new Book { Id = b.Id, Title = b.Title, Published = b.Published, AuthorId = b.AuthorId } ).ToList(); // Authors作成 var authorList = authors.Select( author => { var authorsBooks = bookList.Where(b => author.Id == b.AuthorId).ToList(); // 著者作成 var instance = new Author { Id = author.Id, LastName = author.LastName, FirstName = author.FirstName, Books = authorsBooks }; return instance; } ).ToList(); authorList.ForEach(a => Console.WriteLine(a.ToString())); } /// <summary> /// SQL UPDATE テスト /// </summary> static void Update() { var sqlList = new List<string> { @"UPDATE AUTHORS SET LastName = @LastName WHERE Id = @Id" }; var targetList = new List<object> { new Author { Id = 1, LastName = "LastName 1(改)" } }; int affected = DB.ExecuteNonQuery(sqlList, targetList); Console.WriteLine("affected: {0}", affected); Select(); } /// <summary> /// SQL INSERT テスト /// </summary> static void Insert() { var sqlList = new List<string> { @"INSERT INTO Test.dbo.Authors(Id, LastName, FirstName)VALUES(@Id, @LastName, @FirstName)", @"INSERT INTO Test.dbo.Authors(Id, LastName, FirstName)VALUES(@Id, @LastName, @FirstName)" }; var targetList = new List<object>{ new Author { Id = 1, LastName = "Author LastName 1", FirstName = "Author FirstName 1"}, new Author { Id = 2, LastName = "Author LastName 2", FirstName = "Author FirstName 2"}, }; int affected = DB.ExecuteNonQuery(sqlList, targetList); Console.WriteLine("affected: {0}", affected); //Select(); } /// <summary> /// SQL DELETE テスト /// </summary> static void Delete() { var sqlList = new List<string> { @"DELETE FROM AUTHORS WHERE Id = @Id", @"DELETE FROM AUTHORS WHERE Id = @Id" }; var targetList = new List<object>{ new Author { Id = 1 }, new Author { Id = 2 }, }; int affected = DB.ExecuteNonQuery(sqlList, targetList); Console.WriteLine("affected: {0}", affected); Select(); } } }
Entityなクラス群
using System; using System.Collections.Generic; using System.Linq; namespace LibraryDapper.LibraryNS { /// <summary> /// 書籍クラス /// </summary> class Book { /// <summary> /// 書籍ID /// </summary> public int Id { get; set; } /// <summary> /// 書籍名 /// </summary> public string Title { get; set; } /// <summary> /// 出版日 /// </summary> public DateTime Published { get; set; } /// <summary> /// 著者ID /// </summary> public int AuthorId { get; set; } /// <summary> /// 書籍コンストラクタ /// </summary> public Book() { } /// <summary> /// 書籍コンストラクタ /// </summary> /// <param name="id">書籍ID</param> /// <param name="title">書籍名</param> /// <param name="published">出版日</param> /// <param name="authorId">著者ID</param> public Book(int id, string title, DateTime published, int authorId) { this.Id = id; this.Title = title; this.Published = published; this.AuthorId = authorId; } /// <summary> /// 書籍の文字列表現 /// </summary> /// <returns>書籍の文字列表現</returns> public override string ToString() { return String.Format( "Book(Id:{0}, Title:{1}, Published:{2}, AuthorId:{3})", this.Id, this.Title, this.Published, this.AuthorId); } } /// <summary> /// 著者クラス /// </summary> class Author { /// <summary> /// 著者ID /// </summary> public int Id { get; set; } /// <summary> /// 著者名(姓) /// </summary> public string LastName { get; set; } /// <summary> /// 著者名(名) /// </summary> public string FirstName { get; set; } /// <summary> /// 著作物 /// </summary> public List<Book> Books { get; set; } /// <summary> /// 著者コンストラクタ /// </summary> public Author() { } /// <summary> /// 著者コンストラクタ /// </summary> /// <param name="id">著者ID</param> /// <param name="lastName">著者名(姓)</param> /// <param name="firstName">著者名(名)</param> /// <param name="books">著作物</param> public Author(int id, string lastName, string firstName, List<Book> books) { this.Id = id; this.LastName = lastName; this.FirstName = firstName; this.Books = books; } /// <summary> /// 著者の文字列表現 /// </summary> /// <returns>著者の文字列表現</returns> public override string ToString() { var books = this.Books.Select(book => book.ToString()).ToArray(); string format = "Author(Id: {0}, LastName: {1}, FirstName: {2}, Books({3}))"; return String.Format(format, this.Id, this.LastName, this.FirstName, String.Join(", ", books)); } } }