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 를 지원한다.
샘플 예제는 아래 경로에 있다. 일일이 실행해보면 알듯..