Querying Multiple Rows With Dapper

You can use Dapper to access a database and write queries in a more object-oriented manner. For example, it allows you to execute SQL commands and map the resulting data into a list of objects. With Dapper, you can easily select data from a database and project the result into a list of objects.

Dapper provides several methods for selecting data, depending on how you want to work with the data you retrieve.

Method Description
Query Returns an enumerable of dynamic types
Query<T> Returns an enumerable of the type specified by the T parameter
QueryAsync Returns an enumerable of dynamic types asynchronously
QueryAsync<T> Returns an enumerable of the type specified by the T parameter asynchronously

To select data from a table or view using Dapper, you need to create an instance of the IDbConnection interface. Then you can use the Query<T> or QueryAsync<T> method to execute the SELECT query and store the results in a list of objects.

⚡ Insert Thousands of Rows in Seconds

Need to insert large datasets? BulkInsert dramatically reduces database round trips and makes saving thousands of records incredibly fast.

Explore BulkInsert →

Dapper Query

The primary methods used for selecting data are Query and Query<T> and their async counterparts. The difference between Query and Query<T> is that Query returns results as an IEnumerable<dynamic> and the Query<T> returns an IEnumerable of the type specified by the type argument. The following examples query a Product table.

For example, suppose you have a database table called Product. You could use the following code to select all rows from the Product table and project them into a dynamic list of objects:

language-csharp
|
var sql = "SELECT * FROM Product WHERE CategoryID = @categoryID";
var products = connection.Query(sql, new { categoryID = 1 }).ToList();

foreach(var product in products)
{
	Console.WriteLine($"ProductID: {product.ProductID}; Name: {product.Name}");
}	

Online Example

Note that there is no explicit call to open the connection in the code above. Instead, Dapper will check the state of the connection and open it if it is closed.

Working with dynamic types should ordinarily be avoided because the risk of introducing run-time errors is high. It can be easy to mistype a property name, especially as they are case-sensitive. For example, if you referred to the key column as ProductId instead of ProductID, there would be no help from IntelliSense or exceptions raised. Nothing would be output to the console window at all. Therefore the recommendation is to use the Query<T> methods that take a type parameter representing the data type that the query returns.

The next example works with a Product type, which, following the table schema, has the following definition:

language-csharp
|
public class Product
{
	public int ProductID { get; set; }
	public int CategoryID { get; set; }
	public string Name { get; set; }
	public string Description { get; set; }		
}

The following example is identical to the first one except for the presence of the <Product> type parameter:

language-csharp
|
var sql = "SELECT * FROM Product WHERE CategoryID = @categoryID";
var products = connection.Query<Product>(sql, new { categoryID = 1 }).ToList();

foreach(var product in products)
{
	Console.WriteLine($"ProductID: {product.ProductID}; Name: {product.Name}");
}

Online Example

Dapper QueryAsync

To execute the query asynchronously, Dapper provides the QueryAsync method, an asynchronous version of the Query method.

language-csharp
|
var sql = "SELECT * FROM Product WHERE CategoryID = @categoryID";
var products = (await connection.QueryAsync(sql, new { categoryID = 1 })).ToList();

foreach(var product in products)
{
	Console.WriteLine($"ProductID: {product.ProductID}; Name: {product.Name}");
}	

Online Example

The asynchronous version of the Query<T> method is QueryAsync<T>:

language-csharp
|
using (var connection = new SqlConnection(connectionString))
{
    var sql = "SELECT * FROM Customers";
    var customers = await connection.QueryAsync<Customer>(sql);
	
    foreach(var customer in customers)
    {
        Console.WriteLine($"{customer.CustomerID} {customer.CompanyName}");
    }
}

Online Example

Note if you want to use QueryAsync with buffered = false, you should use instead the QueryUnbufferedAsync method.

FAQ

How to retrieve multiple rows returned by a stored procedure in Dapper?

To retrieve multiple rows returned by a stored procedure, you need to specify the stored procedure name in the command text and specify the command type to CommandType.StoredProcedure.

  1. First, create your stored procedure:
CREATE PROCEDURE MyStoredProcedure
AS
BEGIN
    SELECT * FROM Customer
END
  1. Map the returned data to an anonymous type or a strongly typed object:
using (var connection = new SqlConnection("connectionString"))
{
    var result = connection.Query("MyStoredProcedure", commandType: CommandType.StoredProcedure).ToList();
}
public class Customer
{
    public int CustomerID { get; set; }
    public string Name { get; set; }
	
    // Add other properties as needed, to match all columns returned by the stored procedure
}
	
using (var connection = new SqlConnection("connectionString"))
{
    var result = connection.Query<Customer>("MyStoredProcedure", commandType: CommandType.StoredProcedure).ToList();
}

What does the buffered parameter do for the Query and QueryAsync methods in Dapper?

The buffered parameter in Dapper for the Query and QueryAsync methods controls whether the results of a query are loaded into memory all at once (buffered) or streamed one by one (unbuffered). If set to true (the default), all the data from the query is loaded into memory immediately. If set to false, each row is loaded and processed one at a time, saving memory but potentially increasing execution time.

// Query result will be streamed one by one when `buffered = false`
var customers = connection.Query<Customer>(sql, buffered: false);


Date Modified: 2025-07-10
Author:

Edit this page in GitHub

Got any Dapper Question?