재우니의 블로그


Execute a query and map the results to a strongly typed List Note: all extension methods assume the connection is already open, they will fail if the connection is closed.

이는 쿼리를 실행하고, strongly typed List 형태로 결과값을 매핑하는 것을 의미한다. 참고 : 모든 확장 메소드들은 연결자가 항상 열러져 있기 때문에 connection 이 닫혀 있을 경우 fail 이 떨어진다.

public static IEnumerable<T> Query<T>(this IDbConnection cnn, 
      string sql, object param = null, 
      SqlTransaction transaction = null, 
      bool buffered = true) 
사용 예제 :
public class Dog
{
    public int? Age { get; set; }
    public Guid Id { get; set; }
    public string Name { get; set; }
    public float? Weight { get; set; }

    public int IgnoredProperty { get { return 1; } }
}           
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });

dog.Count()
    .IsEqualTo(1);

dog.First().Age
    .IsNull();

dog.First().Id
    .IsEqualTo(guid);
dynamic object 의 리스트로 매핑하여 쿼리를 실행하는 방법이다.
IDbConnection cnn, string sql, object param = null, 
                   SqlTransaction transaction = null, bool buffered = true) 
이 메소드는 SQL 을 실행하며, dynamic list 를 반환합니다. 사용 예제 :
var rows = connection.Query("select 1 A, 2 B union all select 3, 4");

((int)rows[0].A)
   .IsEqualTo(1);

((int)rows[0].B)
   .IsEqualTo(2);

((int)rows[1].A)
   .IsEqualTo(3);

((int)rows[1].B)
    .IsEqualTo(4);

Command 를 실행하고, 반환값이 없는 경우,...
public static int Execute(this IDbConnection cnn, string sql, 
          object param = null, SqlTransaction transaction = null) 
사용 예제 :
connection.Execute(@"
  set nocount on 
  create table #t(i int) 
  set nocount off 
  insert #t 
  select @a a union all select @b 
  set nocount on 
  drop table #t", new {a=1, b=2 })
   .IsEqualTo(2);

여러번 command 를 실행하는 방법이다.
connection.Execute(@"insert MyTable(colA, colB) values (@a, @b)",
    new[] { new { a=1, b=1 }, 
            new { a=2, b=2 }, 
            new { a=3, b=3 } 

          }
  ).IsEqualTo(3); // 3 rows inserted: "1,1", "2,2" and "3,3"
이는 약간의 T 에 대해 IEnumerable 구현을 하여 약간의 파라미터를 구성하여 작동한다. 성능은 어떨까? 다른 제품보다 성능이 좋다. 자세한건 여기서 다루지 않고, 아래 사이트에서 확인 바람.


파라미터 화 된 쿼리들은 어떻게 구현할까? 파라미터들은 anonymous class 로 구현하며, 아래 처럼 쉽게 구현한다.
new {A = 1, B = "b"} // A will be mapped to the param @A, B to the param @B 
리스트 지원... 이는 in 쿼리로 구현하는 방법이다. Ids 로 여러개 값을 배열로 넣을 수 있다.
connection.Query<int>("select * from (select 1 as Id union all select 2 union all select 3) as X 
                      where Id in @Ids", new { Ids = new int[] { 1, 2, 3 });
위의 구문을 쉽게 변환한다면...
select * from (select 1 as Id union all select 2 union all select 2 union all select 3) as X 
where Id in (@Ids1, @Ids2, @Ids3)" // @Ids1 = 1 , @Ids2 = 2 , @Ids2 =
Buffered vs UnBuffered 리더 Dapper 는 기본적인 행동은 sql 구문을 실행시켜서, 전체 reader 를 buffer 로 하여 반환한다. 이는 네트워크 시간을 최소화 하기 위함 및 db 에서 lock 을 최소한의 공유를 위함이다. Multi Mapping Dapper 는 하나의 row 를 멀티 object 에 매핑이 가능하다.
var sql = 
@"select * from #Posts p 
left join #Users u on u.Id = p.OwnerId 
Order by p.Id";

var data = connection.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post;});
var post = data.First();

post.Content.IsEqualTo("Sams Post1");
post.Id.IsEqualTo(1);
post.Owner.Name.IsEqualTo("Sam");
post.Owner.Id.IsEqualTo(99);
여기서 중요한건, Dapper 는 id 컬럼이 Id 나 id 로 명명되어 있다. 만약에 primary key 가 다르거나 Id 보다 다른 것로 row 을 wide 하게 split 하고자 한다면, splitOn 파라미터 옵션을 사용해야 합니다. Multiple 결과값 가져오기
var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";

using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
   var customer = multi.Read<Customer>().Single();
   var orders = multi.Read<Order>().ToList();
   var returns = multi.Read<Return>().ToList();
   ...
 

}  
저장프로시저를 실행하는 방법은?
var user = cnn.Query<User>("spGetUser", new {Id = 1}, 
        commandType: CommandType.StoredProcedure).SingleOrDefault(); 
좀더 멋지게 약간 뭔가를 원한다면 아래 처럼 구현도 가능하다.
var p = new DynamicParameters();
p.Add("@a", 11);
p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output);
p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

cnn.Execute("spMagicProc", p, commandType: CommandType.StoredProcedure); 

int b = p.Get<int>("@b");
int c = p.Get<int>("@c"); 
Ansi String 그리고 varchar Dapper 는 varchar 파라미터를 지원합니다. where 조건문으로 varchar 의 column 을 명시하여 실행하고자 한다면, 아래 방법처럼 하면 된다.
Query<Thing>("select * from Thing where Name = @Name", 
         new {Name = new DbString { Value = "abcde", IsFixedLength = true, Length = 10, IsAnsi = true }
);
참고로.. sql server 에서 unicode 로 쿼리하면 unicode 로 처리하고, 그게 아니면 ansi 로 처리하면 된다. Dapper 는 SQLite, SQL CE, Firebird, Oracle, MySQL, PostgreSQL and SQL Server 를 지원한다. 샘플 예제는 아래 경로에 있다. 일일이 실행해보면 알듯..