Multiple Query
This feature allows you to fetch multiple result sets in a single database call. Both ExecuteQueryMultiple and QueryMultiple operations are provided for this purpose.
ExecuteQueryMultiple accepts a raw SQL statement, while QueryMultiple accepts a Linq-based query expression and generates the SQL statement automatically.
Both operations abstract the Read() and NextResult() methods of the DbDataReader object.
Type of Return Types
ExecuteQueryMultiple returns an instance of QueryMultipleExtractor, which provides control over how result sets are extracted. Execution is deferred until explicit calls to the Extract() or Scalar() methods are made.
QueryMultiple returns a Tuple instance with a maximum of 7 generic types, matching the maximum defined for Tuple. The item properties of the tuple correspond to the order of the generic types passed during the call.
Hints
For ExecuteQueryMultiple, hints are written directly in the SQL statement. For QueryMultiple, each query in the execution has a corresponding hints argument.
var (customers, orders) = connection.QueryMultiple<Customer, Order>(c => c.Id == customerId, // Customer
o => o.CustomerId == customerId, // Order
hints1: "WITH (NOLOCK)", // Hints for Customer
hints2: "WITH (NOLOCK)"); // Hints for Order
Use the SqlServerTableHints class to simplify hint values:
var (customers, orders) = connection.QueryMultiple<Customer, Order>(c => c.Id == customerId, // Customer
o => o.CustomerId == customerId, // Order
hints1: SqlServerTableHints.NoLock, // Hints for Customer
hints2: SqlServerTableHints.NoLock); // Hints for Order
Ordering
For ExecuteQueryMultiple, ordering is written directly into the SQL statement. For QueryMultiple, each query has a corresponding orderBy argument via the OrderField class.
var (customers, orders) = connection.QueryMultiple<Customer, Order>(c => c.Id == customerId, // Customer
o => o.CustomerId == customerId, // Order
orderBy1: OrderField.Ascending<Customer>(c => c.DateInsertedUtc), // Ordering for Customer
orderBy2: OrderField.Ascending<Order>(o => o.OrderDateUtc)); // Ordering for Order
Filtering
For ExecuteQueryMultiple, filtering is written using TOP or LIMIT in the SQL statement. For QueryMultiple, each query has a corresponding top argument.
var (customers, orders) = connection.QueryMultiple<Customer, Order>(c => c.Id == customerId, // Customer
o => o.CustomerId == customerId, // Order
top2: 10); // Filtering for Order
Single Parent with Multiple Children
For raw SQL, use the ExecuteQueryMultiple method:
using (var connection = new SqlConnection(connectionString))
{
using (var extractor = connection.ExecuteQueryMultiple(@"SELECT * FROM [dbo].[Customer] WITH (NOLOCK) WHERE [Id] = @CustomerId;
SELECT * FROM [dbo].[Order] WITH (NOLOCK) WHERE [CustomerId] = @CustomerId;",
new { CustomerId = 10045 }))
{
// Extract the first result
var customer = extractor.Extract<Customer>().FirstOrDefault();
// Extract the second result
var orders = extractor.Extract<Order>().AsList();
// Set the child orders
customer.Orders = orders;
// Process the 'customer' here
}
}
For the fluent method, use QueryMultiple:
using (var connection = new SqlConnection(connectionString))
{
// The target key
var customerId = 10045;
// Execution by passing the order of entity
var (customers, orders) = connection
.QueryMultiple<Customer, Order>(c => c.Id == customerId, // Customer
o => o.CustomerId == customerId, // Order
hints1: SqlServerTableHints.NoLock, // Hints for Customer
hints2: SqlServerTableHints.NoLock); // Hints for Order
// Extract the customer
var customer = customers.FirstOrDefault();
// Extract the orders
customer.Orders = orders.AsList();
// Process the 'customer' here
}
Querying Multiple Parent and Multiple Children
For raw SQL, use the ExecuteQueryMultiple method:
using (var connection = new SqlConnection(connectionString))
{
using (var extractor = connection.ExecuteQueryMultiple(@"SELECT [Id], [Name] FROM [dbo].[Customer] WITH (NOLOCK) WHERE [Id] IN (@Keys);
SELECT [Id], [CustomerId], [ProductId], [Price], [Quantity], [OrderDateUtc] FROM [dbo].[Order] WITH (NOLOCK) WHERE [CustomerId] IN (@Keys);",
new { Keys = new [] { 10045, ..., 11211 }))
{
// Extract the first result
var customers = extractor.Extract<Customer>().AsList();
// Extract the second result
var orders = extractor.Extract<Order>();
// Iterate the customers and map all the orders
customers.ForEach(
c => c.Orders = orders.Where(o => o.CustomerId == c.Id).AsList());
// Process the 'customers' here
}
}
For the fluent method, use QueryMultiple:
using (var connection = new SqlConnection(connectionString))
{
// List of keys to query
var keys = new [] { 10045, ..., 11211 };
// Execution by passing the order of types
var (customers, orders) = connection
.QueryMultiple<Customer, Order>(c => keys.Contains(c.Id), o => keys.Contains(o.CustomerId),
hints1: SqlServerTableHints.NoLock, hints2: SqlServerTableHints.NoLock);
// Iterate the customers and map all the orders
customers.AsList().ForEach(
c => c.Orders = orders.Where(o => o.CustomerId == c.Id).AsList());
// Process the 'customers' here
}
Please visit our Multiple Resultsets reference implementation page for more details.